我试图创建在类中定义的static constexpr
。我知道这个问题:static constexpr member of same type as class being defined,方法3现在运行正常。
但是,我的链接器有问题。它报告了重复的符号,可能是因为const
到constexpr
重新定义。有没有办法实现这个目标?我正在使用xcode 7。
我正在尝试的代码是:
class foo{
int _x;
constexpr foo(int x) : _x(x) {}
public:
static const foo a, b, c;
constexpr int x() const { return _x; }
};
constexpr foo foo::a = foo(1), foo::b = foo(2), foo::c = foo(1);
在多个地方包含此文件会导致链接器错误说明
3 duplicate symbols for architecture x86_64
我知道这是问题,因为如果我只在它工作正常时才包含它。
答案 0 :(得分:3)
好吧,你定义前三个静态const变量然后你将它们定义为constexpr。由于constexpr静态成员必须是完整的,因此它不能在类本身的范围内。您的代码应如下所示:
class foo {
int _x;
public:
constexpr foo(int x) : _x(x) {}
constexpr int x() const { return _x; }
};
constexpr foo a = foo{1}, b = foo{2}, c = foo{1};
如果你仍然希望将foo作为静态成员,你可以做这个小技巧:
class foo {
int _x;
constexpr foo(int x) : _x(x) {}
struct constants;
public:
constexpr int x() const { return _x; }
};
struct foo::constants {
constexpr static foo a = foo{1}, b = foo{2}, c = foo{1};
};
如果您使用的是C ++ 14及之前,请执行此操作。在C ++ 17中,所有constexpr静态数据成员都是隐式内联的。
现在为什么会出现链接错误?
这个小规则称为一个定义规则,它规定在所有编译单元中可以有任意数量的声明但只有一个定义。通过您在问题中包含的代码段,您似乎在标题中定义了静态成员。如果有两个包含标题的编译单元,则会违反规则。使用上面的代码示例,您不应再有此错误,而是另一个错误:没有定义。 constexpr值可能在编译时使用,但在运行时不可用。为此,您必须在.cpp文件中声明:
#include "foo.h"
constexpr foo foo::constants::a;
constexpr foo foo::constants::b;
constexpr foo foo::constants::c;
现在正确声明和定义了三个静态变量。
答案 1 :(得分:1)
与任何变量定义一样,您只应将其放在一个翻译单元中。
将最后一行移出标题。
答案 2 :(得分:1)
除了Guillaume Racicot的回答,您还可以添加constexpr函数,该函数返回constexpr值的复制或const引用,该值在其他地方定义。或者每次调用构造函数并返回新的instane,而不保留constexpr变量。 在VS2015上测试:
class foo {
int _x;
constexpr foo(int x) : _x(x) {}
struct constants;
public:
constexpr int x() const { return _x; }
static constexpr const foo &a();
static constexpr const foo &b();
static constexpr const foo &c();
static constexpr foo d() { return foo(5); }
};
struct foo::constants {
constexpr static foo a = foo{ 1 }, b = foo{ 2 }, c = foo{ 1 };
};
constexpr const foo &foo::a() { return constants::a; }
constexpr const foo &foo::b() { return constants::b; }
constexpr const foo &foo::c() { return constants::c; }
然后你可以从foo的范围中获取值,例如:static_assert(foo::a().x()==1,"");
答案 3 :(得分:0)
移动
constexpr foo foo :: a = foo(1),foo :: b = foo(2),foo :: c = foo(1);
行到.cc
文件。该行定义变量。变量可以根据需要多次声明,但只能在整个二进制文件中定义一次。