我有这个非常简单的函数,我有一些值需要计算,但只需要一次,最好的时间是在编译时.这些值仅在此函数中有效.这是constexpr的好用还是我应该只声明它们是静态const?
ps我知道性能差异是无关紧要的,但我想用"正确"的c ++ 11方式做到这一点.
void MainWindow::UpdateDateTimes()
{
// for some dumb reason DateTime only has add seconds method
// so we have to calculate the seconds per hour and the number of hours
// we do this with static constant values so that the calculations
// only happen once.
static constexpr const int secsPerHour = 60 * 60;
static constexpr const int cdtOffsetHours = -5;
static constexpr const int edtOffsetHours = -4;
static constexpr const int cetOffsetHours = 2;
static …Run Code Online (Sandbox Code Playgroud) 在观看isocpp.org上链接的C++ 11教程视频时,我注意到了一些事情:
constexpr int windowWidth{800}, windowHeight{600};
Run Code Online (Sandbox Code Playgroud)
声明这些int变量有什么意义constexpr,而不仅仅是const?
考虑F一个constexpr size_t参数的函数对象I
struct F
{
template <size_t I>
constexpr size_t operator()(size <I>) const { return I; }
};
Run Code Online (Sandbox Code Playgroud)
包裹在一个类型中size <I>,其中(为简洁起见)
template <size_t N>
using size = std::integral_constant <size_t, N>;
Run Code Online (Sandbox Code Playgroud)
当然,我们可以I直接传递,但我想通过使用它作为模板参数强调它是constexpr.函数F在这里是虚拟的,但实际上它可以做各种有用的东西,比如从I元组的元素中检索信息.F假定具有相同的返回类型,无论如何I.I可以是任何整数类型,但假设是非负的.
问题
给定一个constexpr size_t值I,我们可以调用F由
F()(size <I>());
Run Code Online (Sandbox Code Playgroud)
现在,如果我们想F用非constepr size_t值调用i怎么办?考虑以下:
constexpr size_t L = 10;
idx <F, L> f;
for (size_t i = …Run Code Online (Sandbox Code Playgroud) 我有以下代码:
struct Literal
{
int val;
constexpr Literal(int const& val) : val(val) {}
constexpr Literal(Literal const& rhs) : val(rhs.val) {}
};
struct Parent
{
struct StaticObject
{
Literal const zero;
constexpr StaticObject() :zero(0) {}
};
static constexpr StaticObject outer{};
};
Run Code Online (Sandbox Code Playgroud)
行'static constexpr StaticObject outer {};' 给我错误:
'表达式没有评估为常数'
接下来是
注意:失败是由调用未定义的函数或未声明'constexpr'的函数引起的
注意:请参阅'Parent :: StaticObject :: StaticObject'的用法
据我所知,这里使用的所有函数都是定义和声明的constexpr.我错过了什么,或者这是一个编译器错误?
我使用以下代码访问某些MCU寄存器.
#include <stdint.h>
struct MCU {
struct Timer {
volatile uint8_t r1;
template<int N> struct Address;
};
};
template<>
struct MCU::Timer::Address<0> {
static constexpr uint8_t value = 0x25;
};
template<typename Component, int Number>
constexpr Component* getBaseAddr() {
return reinterpret_cast<Component*>(Component::template Address<Number>::value);
}
struct Test {
static void foo() {
p->r1 = 42;
}
static constexpr auto p = getBaseAddr<MCU::Timer, 0>();
};
int main() {
Test::foo();
while(true) {}
}
Run Code Online (Sandbox Code Playgroud)
在avr-g ++ 6.2.1中,这很好用.但现在使用avr-g ++ 7.0我得到错误:
in constexpr expansion of 'getBaseAddr<MCU::Timer, 0>()'
bm10a.cc:23:58: error: …Run Code Online (Sandbox Code Playgroud) 在C ++ 14标准(ISO / IEC 14882:2014)中,第5.19节第2款(强调我的)中添加了“ 不可更改 ”一词:
甲条件表达式 e是一个核心常量表达式除非e的评价,如下所述抽象机(1.9),将评估下面的表达式中的一个的规则:
- [...]
- 左值到右值转换(4.1),除非将其应用于
- [...]
- 非易失性glvalue,它引用用constexpr定义的非易失性对象,或引用该对象的不可更改子对象,或者
因此,此代码在C ++ 14中不正确:
class A {
public:
mutable int x;
};
int main(){
constexpr A a = {1};
constexpr int y = a.x;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是,在C ++ 11中是否正确?
这是缺陷报告(CD3)1405,他们提议在其中添加非可变的:
当前,文字类类型可以具有可变成员。尚不清楚这是否会对constexpr对象和常量表达式造成任何特殊的问题,如果是这样,应该如何处理。
所以我会说这是正确的C ++ 11代码。尽管如此,我还是使用-std = c ++ 11尝试了Clang和GCC,并且都输出了一个错误,指出常量表达式中不允许使用可变变量。但是该约束是在C ++ 14中添加的,而在C ++ 11中则没有。
有谁知道该代码在C ++ 11中是否正确?
另请参阅缺陷报告(CD3)1428。
我在链接我的目标文件时收到错误:
#include <cstdint>
#include <array>
enum SystemType : uint8_t { AC, DC, HCP, EFF };
template<SystemType TYPE> struct System;
template<>
struct System<AC> {
public:
static constexpr size_t number_of_sockets = 2;
static constexpr std::array<size_t, number_of_sockets> object_per_socket { { 12, 6 } };
};
Run Code Online (Sandbox Code Playgroud)
我正在使用它如下所示将数据分配到向量中.
terminal->no_obj_per_system.assign(
Sytem<AC>::object_per_socket.begin(),
Sytem<AC>::object_per_socket.end());
Run Code Online (Sandbox Code Playgroud)
我在mac Os上使用clang.
在下面的程序中,我添加了一个显式return语句func(),但编译器给出了以下错误:
m.cpp: In function ‘constexpr int func(int)’:
m.cpp:11:1: error: body of constexpr function ‘constexpr int func(int)’ not a return-statement
}
Run Code Online (Sandbox Code Playgroud)
这是代码:
#include <iostream>
using namespace std;
constexpr int func (int x);
constexpr int func (int x)
{
if (x<0)
x = -x;
return x; // An explicit return statement
}
int main()
{
int ret = func(10);
cout<<ret<<endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我使用以下命令在g ++编译器中编译了程序.
g++ -std=c++11 m.cpp
Run Code Online (Sandbox Code Playgroud)
我return在函数中添加了语句,然后为什么我出现上述错误?
我正在尝试学习一些更现代的C++实践,比如模板,我决定创建一个天真简单的命令行参数解析器,它主要在编译时工作,我已经constexpr遇到了问题,基本上我想做的就是检查对于编译时的重复条目(在运行时执行它是微不足道的).
首先,我有一个包含单个配置的结构:
struct Arg_Opt_Tuple {
std::string_view mc{}; // multichar ie "help"
char sc{}; // singlechar ie 'h'
bool is_flag{};
};
Run Code Online (Sandbox Code Playgroud)
现在让我们说我想创建一个函数(或者最终是对象的构造函数),它返回一个固定大小的std :: array,但是在编译时也会检查重复项或空值,我的目标是让它调用一些与此类似的时尚:
constexpr auto ARG_COUNT = 4U;
constexpr auto opts = checked_arr<ARG_COUNT>(
Arg_Opt_Tuple{"hello", 'h', false},
Arg_Opt_Tuple{"world", 'g', true},
Arg_Opt_Tuple{"goodbye", 'h', false}, // <- static_assert('h' == 'h')
Arg_Opt_Tuple{"hello", 'r', false} // <- static_assert(sv.compare("hello") == 0)
);
Run Code Online (Sandbox Code Playgroud)
我的第一次尝试是使用std :: initializer_list但遇到了一些问题,在做了一些谷歌搜索结束后得出结论与constexpr一起做的不正确.我目前的尝试涉及一个可变参数模板:
template <std::size_t N, typename... T>
constexpr std::array<Arg_Opt_Tuple, N> checked_arr(T... list) {
static_assert(N == sizeof...(T));
return {list...};
}
Run Code Online (Sandbox Code Playgroud)
这可以工作,但对于只是初始化一个数组是完全多余的,我真的希望这是做一些编译时间检查.对于重复或错误的值在运行时很容易,你可以循环并比较或做std :: …
template <typename T>
inline constexpr int a = 1;
static_assert(&a<void>, "");
Run Code Online (Sandbox Code Playgroud)
这不会在gcc 9.2上进行编译,但是会在clang和msvc上进行编译。
Gcc抱怨用于的表达式static_assert不是常量表达式。
The code compiles after removing template, removing inline, or removing address-of operator.
Is this a gcc bug?