Mic*_*eyn 66 c++ constexpr c++11
让我先说明我的意图.在旧的(C++)时代,我们会有如下代码:
class C
{
public:
enum {SOME_VALUE=27};
};
Run Code Online (Sandbox Code Playgroud)
然后我们可以SOME_VALUE在整个代码中使用编译时常量,无论编译器在哪里看C::SOME_VALUE,它都只是插入文字27.
现在,将代码更改为以下内容似乎更为可接受:
class C
{
public:
static constexpr int SOME_VALUE=27;
};
Run Code Online (Sandbox Code Playgroud)
这看起来更清晰,提供SOME_VALUE了一个定义良好的类型,并且似乎是C++ 11中的首选方法.(至少对我来说不可靠)问题是,这也导致SOME_VALUE需要在外部进行的情况.也就是说,在某个地方的某个cpp文件中,我们需要添加:
constexpr int C::SOME_VALUE; // Now C::SOME_VALUE has external linkage
Run Code Online (Sandbox Code Playgroud)
导致这种情况的情况似乎是在使用const引用时SOME_VALUE,这在C++标准库代码中经常发生(请参阅本问题底部的示例).顺便说一句,我使用gcc 4.7.2作为我的编译器.
由于这种困境,我被迫恢复定义SOME_VALUE为枚举(即旧学校),以避免必须为某些(但不是所有)静态constexpr成员变量的cpp文件添加定义.是不是有某种方法告诉编译器这constexpr int SOME_VALUE=27意味着SOME_VALUE应该只将其视为编译时常量而不是具有外部链接的对象?如果您看到与它一起使用的const引用,请创建一个临时引用.如果你看到它的地址,如果需要的话就会产生编译时错误,因为它是编译时常量而已.
以下是一些看似良性的示例代码,它们使我们需要SOME_VALUE在cpp文件中添加定义(再次使用gcc 4.7.2进行测试):
#include <vector>
class C
{
public:
static constexpr int SOME_VALUE=5;
};
int main()
{
std::vector<int> iv;
iv.push_back(C::SOME_VALUE); // Will cause an undefined reference error
// at link time, because the compiler isn't smart
// enough to treat C::SOME_VALUE as the literal 5
// even though it's obvious at compile time
}
Run Code Online (Sandbox Code Playgroud)
将以下行添加到文件范围的代码将解决该错误:
constexpr int C::SOME_VALUE;
Run Code Online (Sandbox Code Playgroud)
这里有三个选项:
如果您的类是模板,那么将静态成员的定义放在标题本身中.编译器需要仅在多个翻译单元中将其标识为一个定义(参见[basic.def.odr]/5)
如果您的类是非模板,则可以轻松将其放入源文件中
或者声明constexpr静态成员函数getSomeValue():
class C
{
public:
static constexpr int getSomeValue() { return 27; }
};
Run Code Online (Sandbox Code Playgroud)对于记录,该static constexpr版本将像您在C++ 17中所期望的那样工作.来自N4618附件D.1 [depr.static_constexpr]:
D.1
static constexpr数据成员的重新声明[depr.static_constexpr]为了与先前的C++国际标准兼容,
constexpr可以在类外部冗余地重新声明静态数据成员而不使用初始化程序.不推荐使用此用法.[ 例如:
struct A {
static constexpr int n = 5; // de?nition (declaration in C++ 2014)
};
constexpr int A::n; // redundant declaration (de?nition in C++ 2014)
Run Code Online (Sandbox Code Playgroud)
- 结束例子 ]
允许这样做的相关标准文本是N4618 9.2.3 [class.static.data]/3:
[...]内联静态数据成员可以在类定义中定义,并且可以指定括号或等于初始化器.如果使用
constexpr指定者声明成员,则可以在没有初始化程序的命名空间作用域中重新声明该成员(此用法已弃用;请参阅D.1).[...]
这与引入相同内容的非constexpr版本的内联静态数据成员的机器相同.
struct A {
static inline int n = 5; // de?nition (illegal in C++ 2014)
};
inline int A::n; // illegal
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12424 次 |
| 最近记录: |