这更像是一个哲学问题,而不是实际的代码片段,但也许C++专家可以启发我(并且如果已经被问过就道歉).
我一直在阅读Meyers的"Effective Modern C++"一书中的第15项,以及这个主题:隐含的constexpr?(加上合理数量的谷歌搜索).该项目constexpr用于表达式的使用,即它定义了在给定编译时输入的情况下可以返回编译时间值的函数.此外,我提到的StackOverflow线程表明,一些编译器完全能够自己计算出哪些函数调用结果在编译时是已知的.
因此,问题是:constexpr与定义何时编译器应该派生并允许静态/编译时值相比,为什么添加到标准中?
我意识到这使得各种仅限编译(例如std::array<T, constexpr>)的定义不太可预测,但另一方面,根据Meyers的书,constexpr是界面的一部分,...,如果你删除它,你可能会造成任意大量的客户端代码停止编译.因此,不仅有明确的constexpr要求人们记住添加它,它还会为接口添加永久语义.
澄清:这个问题不是为什么constexpr要使用.我很欣赏能够以编程方式获得编译时值非常有用,并且在很多场合自己使用它.这是一个问题,为什么在编译器可能自己推断出const-time行为的情况下它是强制性的.
澄清号码 2:这是一个代码片段,显示编译器不会自动推断出,我在这种情况下使用了g ++.
#include <array>
size_t test()
{
return 42;
}
int main()
{
auto i = test();
std::array<int, i> arrayTst;
arrayTst[1] = 20;
return arrayTst[1];
}
Run Code Online (Sandbox Code Playgroud)
std::array声明无法编译,因为我没有定义test()为constexpr,这当然是按照标准.如果标准不同,那么没有任何东西可以阻止gcc独立计算test()总是返回一个常量表达式.
这个问题不是问"标准定义了什么",而是"为什么标准就是这样"?
我有这个伪位域实现:
class Field {
public:
constexpr Field(int i, int s) : index(i), size(s) {}
constexpr Field(const Field & prev, int s) : index(prev.index + prev.size), size(s) {}
int index, size;
};
#define FIELD(name, i, s) constexpr static const Field name = {i, s};
template<typename T = quint32>
class Flags {
public:
Flags(T d = 0) : data(d) {}
inline T readField(const Field & f) {
return (data & getMask(f.index, f.size)) >> f.index;
}
inline void writeField(const Field & f, T …Run Code Online (Sandbox Code Playgroud) 我遇到了一个我不明白的情况.有人会这么好解释为什么第一个代码正确编译而第二个代码出错:
错误:'TestClass :: z'的值在常量表达式中不可用
static constexpr int sum(){return x + y + z;}
----------------- ----------------------------------- ^
注意:'int TestClass :: z'不是const static int Z者除外;"
工作代码:
#include <iostream>
using namespace std;
class TestClass
{
public:
constexpr int sum() {return x+y+z;}
private:
static constexpr int x = 2;
static const int y = 3;
int z = 5;
};
int main()
{
TestClass tc;
cout << tc.sum() << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是当我尝试制作TestClass::sum()静态时,我得到了上述错误:
#include <iostream>
using namespace std;
class TestClass
{ …Run Code Online (Sandbox Code Playgroud) 我发现了一个bug在GCC 6和7(未在GCC 5)内constexpr功能,这导致不同的结果,如果任一函数获取在编译时(错误的结果),或运行时(正确结果)的计算结果.
#include <iostream>
constexpr int bar(int *b) {
int i = 0;
b[i++] = 1; // GCC produce here an failure.
return 0;
}
constexpr int foo()
{
int tmp[] = {0};
bar(tmp);
return tmp[0];
}
constexpr int cexprI = foo();
int main()
{
std::cout << cexprI << " " << foo() << "\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
问题是数组访问中的增量(也发生在减量)操作.
常量表达式的编译时结果为0(错误),运行时结果为1(正确).
任何人都可以确认此错误并报告给:https://gcc.gnu.org/bugzilla/
我无法在那里创建一个帐户User account creation has been restricted..我联系了管理员,但对我来说这个问题很重要.所以它也想通知你.谢谢!
以下代码不能用g ++/clang ++编译.
constexpr int bar(int v) {
if (v > 0){
return v * 2;
}
return 2;
}
constexpr int foo(const int v) {
constexpr auto x = bar(v); // error
return v;
}
int main() {
constexpr auto a = foo(1);
constexpr auto b = bar(1); // ok
}
Run Code Online (Sandbox Code Playgroud)
错误消息是:x必须由常量表达式初始化
但是从行(ok)你看到bar()是constexpr.
如果我将foo()的主体改为
constexpr int foo(const int v) {
return bar(v);
}
Run Code Online (Sandbox Code Playgroud)
没关系!
我不清楚,为什么第一种形式不可能.我使用g ++ - 6.2.1,g ++ - 7.0.0和clang ++ - 3.9.0
我试图弄清楚是否有通过constexpr而不是正常创建对象的性能提升.
这是代码片段constexpr.
class Rect
{
const int a;
const float b;
public:
constexpr Rect(const int a,const float b)
: a(a),b(b){}
};
int main()
{
constexpr Rect rect = Rect(1,2.0f);
}
Run Code Online (Sandbox Code Playgroud)
没有constexpr.
class Rect
{
int a;
float b;
public:
Rect(int a, float b)
: a(a),b(b){}
};
int main()
{
Rect rect = Rect(1,2.0f);
}
Run Code Online (Sandbox Code Playgroud)
constexpr因为内存应该在编译时初始化,所以我期待会有更少的代码.
我使用constexpr得当吗?如果不是这样,你可以使用constexpr在编译时创建对象,然后在没有任何运行时开销的情况下使用它们吗?
谢谢!
我已经阅读了与此问题相关的所有答案,但老实说,我不确定我是否完全理解该解决方案.我正在使用C++ 11.
让我们说我真的想宣布类似的东西static constexpr char value[] = "foo".
如果我使用NetBeans/TDM_MINGW,我会收到一个错误,我认为这是一个链接错误,报告对"variable_name"的未定义引用.
在MS VS 2015中尝试相同的代码我得到"表达式没有评估为常量".
一个简单的static constexpr char *解决了问题,但我失去了使用表达式的能力sizeof.
简单直接的问题(如果可能的话,直截了当的问题):
static constexpr char []内部struct/ class?static constexpr char *????static const char []的仍然是这种情况的最佳方法?static constexpr array<char,50> getConstExpr(){
return array<char,50> {"Hell"}
}.它工作正常,但我必须声明char的大小std::array:(在下面的示例main中,static_assert如果字符串文字以开头'v',则verify可以,但是不能。
为什么会这样呢?有没有一种方法可以verify对static_assert字符串文字中的字符进行条件设置?
#include <cstddef>
template <std::size_t N>
constexpr char get_first(const char (&str)[N])
{
static_assert(N>1, "must be > 1");
return str[0];
}
template <std::size_t N>
constexpr void verify(const char (&str)[N])
{
static_assert(str[0] == 'v', "must start from v");
}
int main()
{
static_assert(get_first("value") == 'v', "first must be 'v'"); // succeeds
verify("value"); // fails to compile
}
Run Code Online (Sandbox Code Playgroud)
编译错误:
main.cpp: In instantiation of 'constexpr void verify(const char (&)[N]) [with long …Run Code Online (Sandbox Code Playgroud) (这是一个XY问题,但请耐心等待.)
我收到关于换档量太大的编译警告.现在,为了诊断这一点,我希望我的编译器以某种方式发出constexpr用作移位量的值.
到目前为止我完成它的方法是尝试使用数字参数实例化一个类型,我知道我可以将其放在范围之外,然后添加我想要的constexpr值并得到一个显示总和的错误.但这是一个丑陋的黑客.有没有办法让constexpr值(希望不仅仅是整数)发送到标准错误流?例如,连同一些解释性文字或警告信息?
我问的是GCC 6.x以及后来的clang 4.x及更高版本.
在下面的代码main返回2,而我希望它返回0(或至少7)
extern struct S s;
template<typename T>
constexpr int global(T&) { return 0; }
template<typename T>
//constexpr
int func(T& t) { return global(t); }
int main()
{
return global(s) + 2*func(s) + 4*([](auto &a){return global(a);})(s);
}
static constexpr int global(S&) { return 1; }
Run Code Online (Sandbox Code Playgroud)
该代码也位于https://godbolt.org/z/RkkXwf
如果我constexpr对func结果不加评论,则更改为预期值0。
据我了解,重载解析应该只在模板实例化点之前考虑函数。但是不知何故,它找到了在此之后声明的上下文,既不constexpr是通用lambda ,也不是通用lambda。
为什么这三个查询找到不同的功能?