我正在尝试使用lambda作为静态成员,如下所示:
struct A
{
static constexpr auto F = [](){};
};
int main()
{
A::F();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是否是正确的C++ 11代码?在clang上,我收到此错误:
error: constexpr variable 'F' must be initialized by a constant
expression
static constexpr auto F = [](){};
^~~~~~
Run Code Online (Sandbox Code Playgroud)
似乎在铿锵声中,lambdas不被视为常数表达.它是否正确?也许他们还没有在clang中完全实现lambdas,因为gcc 4.7似乎允许它作为a constexpr,但是它给出了另一个错误:
error: ‘constexpr const<lambda()> A::F’, declared using local type ‘const<lambda()>’, is used but never defined
Run Code Online (Sandbox Code Playgroud)
我不确定,我明白这意味着什么.它似乎正确地推断出lambda的类型,但它只声明它而不是定义它.我该如何定义它?
我已经写了一些代码投const char*来int使用constexpr,因此我可以使用const char*作为一个模板参数.这是代码:
#include <iostream>
class conststr
{
public:
template<std::size_t N>
constexpr conststr(const char(&STR)[N])
:string(STR), size(N-1)
{}
constexpr conststr(const char* STR, std::size_t N)
:string(STR), size(N)
{}
constexpr char operator[](std::size_t n)
{
return n < size ? string[n] : 0;
}
constexpr std::size_t get_size()
{
return size;
}
constexpr const char* get_string()
{
return string;
}
//This method is related with Fowler–Noll–Vo hash function
constexpr unsigned hash(int n=0, unsigned h=2166136261)
{
return n …Run Code Online (Sandbox Code Playgroud) 鉴于源代码中唯一不同的两个程序是否存在constexpr,程序的含义是否可能发生变化?
换句话说,如果有一个编译器选项要求编译器尝试很难推断constexpr可能的地方,它会破坏现有的标准代码和/或以不好的方式改变其含义吗?
想象一下处理一个代码库,原始开发人员忘记将其包含constexpr在可能的地方,也许是在C++ 11之前编写的代码.如果编译器推断constexpr可以帮助您继续工作,那将会很棒.当然,或许它也应该在每次进行推理时发出警告,鼓励你明确添加constexpr后者.但它仍然有用.我担心它会破坏东西吗?
到目前为止,我唯一能想到的是constexpr函数是隐含的,inline并且可能存在添加inline可能以不良方式改变事物的情况; 例如,如果您违反了单定义规则.
也许我错过了一些东西,但我找不到任何提示:C++ 17中有一个constexpr三元运算符,相当于constexpr-if?
template<typename Mode>
class BusAddress {
public:
explicit constexpr BusAddress(Address device) :
mAddress(Mode::write ? (device.mDevice << 1) : (device.mDevice << 1) | 0x01) {}
private:
uint8_t mAddress = 0;
};
Run Code Online (Sandbox Code Playgroud) 考虑一个简单的INT Wrapper与重载乘法类operator*=和operator*.对于"旧式"运算符重载,可以定义operator*,operator*=甚至还有像Boost.Operators这样的库以及@DanielFrey的现代化版本操作符,它们可以为您减少样板.
但是,对于使用新C++ 11的编译时计算constexpr,这种便利性消失了.A constexpr operator*无法调用,operator*=因为后者修改了它的(隐式)左参数.此外,constexpr没有过载,因此constexpr operator*在现有operator*结果中添加额外的过载分辨率模糊.
我目前的做法是:
#include <iostream>
struct Wrap
{
int value;
Wrap& operator*=(Wrap const& rhs)
{ value *= rhs.value; return *this; }
// need to comment this function because of overloading ambiguity with the constexpr version
// friend Wrap operator*(Wrap const& lhs, Wrap const& rhs)
// { return Wrap { …Run Code Online (Sandbox Code Playgroud) 这是有效的代码:
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
const int xVal { 0 };
const int yVal { 0 };
};
Run Code Online (Sandbox Code Playgroud)
但在这里我真的想申报xVal并 - 像yVal constexpr这样:
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
constexpr int xVal { 0 }; // error!
constexpr int yVal { 0 }; // error!
};
Run Code Online (Sandbox Code Playgroud)
如上所示,代码将无法编译.原因是(根据7.1.5/1),只能声明静态数据成员constexpr.但 …
在全局命名空间中给出以下声明:
constexpr int x = x;
Run Code Online (Sandbox Code Playgroud)
这个结构良好吗?
草案C++ 14标准部分3.6.2 [basic.start.init]说:
具有静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)的变量应在任何其他初始化发生之前进行零初始化(8.5).[...]
似乎使得示例定义良好的是x在常量初始化期间使用其自己的值初始化,这将0归因于零初始化.
error: the value of 'x' is not usable in a constant expression
constexpr int x = x;
^
Run Code Online (Sandbox Code Playgroud) 我们显然无法做到一切constexpr.如果我们什么都不做constexpr,那就不会有任何大问题.到目前为止,很多代码都没有编写.
但是打constexpr一些可能有它的东西是个好主意吗?这有什么潜在的问题吗?
有一个众所周知的技巧,constexpr通过执行以下操作来在函数求值中导致编译时错误:
constexpr int f(int x) {
return (x != 0) ? x : throw std::logic_error("Oh no!");
}
Run Code Online (Sandbox Code Playgroud)
如果在constexpr上下文中使用该函数,则会出现编译时错误x == 0.但是,如果参数f不是constexpr,那么它将在运行时抛出异常x == 0,但由于性能原因,这可能并不总是需要.
类似于assert被保护的理论NDEBUG,是否有一种方法可以导致constexpr函数的编译时错误,但是在运行时没有做任何事情?
最后,constexprC++ 1y(C++ 14)中的宽松规则会改变什么吗?
在c ++ 11中,constexpr表达式不能包含重新解释转换.因此,例如,如果想要操纵浮点数中的位,比如找到数字的尾数:
constexpr unsigned int mantissa(float x) {
return ((*(unsigned int*)&x << 9) >> 9);
};
Run Code Online (Sandbox Code Playgroud)
上面的代码将无法实现constexpr.从理论上讲,我无法看到在这个或类似情况下重新解释如何与算术运算符有任何不同,但编译器(和标准)不允许它.
是否有任何巧妙的方法来解决这个限制?