Static constexpr problems with the class inside the class

I am trying to create a static constexpr defined inside a class. I know about this question: the static constexpr member is of the same type as the class being defined , and method 3 now works fine.

However, I have a problem with the linker. It reports repeated characters, possibly due to an override of const to constexpr . Is there any way to do this? I am using xcode 7.

The code I'm trying to do is:

 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); 

Including this file in more than one location results in a linker error

 3 duplicate symbols for architecture x86_64 

I know this is a problem because if I turn it on only after it works fine.

+1
source share
4 answers

Well, you define the first three static constant variables, and then define them as constexpr. Since constexpr static member must be complete, it cannot be within the class itself. Your code should look like this:

 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}; 

If you still want to have foo as a static member, you can do this little trick:

 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}; }; 

Now why is the link error?

There, this little rule is called the Unified Definition Rule, which says that there can be any number of declarations, but one definition for all compilation units. According to your piece of code that you included in your question, it looks like you are defining your static member in your header. If there are two compilation units, including your title, you are breaking the rule. With my sample code above, you should no longer have this error, but instead: there is no definition. the constexpr value can be used at compile time, but will not be used at run time. To do this, you must declare this in a .cpp file:

 #include "foo.h" constexpr foo foo::constants::a; constexpr foo foo::constants::b; constexpr foo foo::constants::c; 

Now your three static variables are correctly declared and defined.

+2
source

Move

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

to the .cc file. This line defines the variables. A variable can be declared as many times as you like, but it is defined only once in your entire binary version.

0
source

As with any variable definition, you must put it in only one translation unit.

Move the last line from your header.

0
source

In addition to Guillaume Racicot's answer, you can add a constexpr function that returns a copy or reference constant for constexpr values โ€‹โ€‹that are defined elsewhere. Or call the constructor and return a new instance each time without saving constexpr variables. Tested on 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; } 

You can then get the values โ€‹โ€‹from the foo scope, for example: static_assert (foo :: a (). X () == 1, "");

0
source

All Articles