Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 类内类链接问题的静态constexpr_C++_C++11_Clang - Fatal编程技术网

C++ 类内类链接问题的静态constexpr

C++ 类内类链接问题的静态constexpr,c++,c++11,clang,C++,C++11,Clang,我试图创建类中定义的静态constexprs。我知道这个问题:,方法3现在可以了 但是,我的链接器有问题。它报告重复符号,可能是因为const到constepr重新定义。有没有办法做到这一点?我使用的是xcode 7 我正在尝试的代码是: class foo{ int _x; constexpr foo(int x) : _x(x) {} public: static const foo a, b, c; constexpr int x() const { ret

我试图创建类中定义的
静态constexpr
s。我知道这个问题:,方法3现在可以了

但是,我的链接器有问题。它报告重复符号,可能是因为
const
constepr
重新定义。有没有办法做到这一点?我使用的是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
我知道这就是问题所在,因为如果只包含一次,它就可以正常工作。

移动

constexpr foo-foo::a=foo(1),foo::b=foo(2),foo::c=foo(1)


行到
.cc
文件。这一行定义了变量。一个变量可以声明任意多次,但只能在整个二进制文件中定义一次。

与任何变量定义一样,您应该只将它放在一个转换单元中


将最后一行移出页眉。

首先定义前三个静态常量变量,然后将它们定义为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;

现在,您的三个静态变量已正确声明和定义。

除了Guillaume Racicot的答案之外,您还可以添加constexpr函数,该函数返回在其他位置定义的constexpr值的copy或const引用。或者每次调用构造函数并返回新实例,而不保留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\u断言(foo::a().x()==1,”

这样做会使它成为一个非
constepr
,使
静态断言(foo::a.x()==1,”)
失败。有没有办法将
常量泄漏到
foo
的范围内?我需要能够编写
foo::a
。那么,
constexpr
静态成员必须是完整的,因此不能直接在类本身中。第二个代码段做了一个小技巧,允许它仍然在
foo
范围内。我还不知道其他的解决方法。