Andrew Lazarus
Andrew Lazarus

Reputation: 19320

Initialize a constexpr array with user-defined literal

Simplified version

class C {
 public:
 static constexpr std::array<C, 2> foo {{"1"_C, "2"_C}};
 int x;
 constexpr C(char c) { x=c; }
}
constexpr C operator"" _C(const char * str, size_t n) { return C(*str); }

This doesn't fly, because the literals are not understood at the line where the array is defined. But the free literal function can't be moved earlier because then C isn't known.

Is there a solution to this Gordian knot that doesn't involve adding variadic templates or something horrid like that into the code?

Upvotes: 2

Views: 685

Answers (1)

Xeo
Xeo

Reputation: 131799

The problem doesn't really lie with user-defined literals, but with the fact that std::array requires complete types (or really, any constexpr initialization does). The following code will also fail to compile:

#include <array>

class C {
public:
 static constexpr std::array<C, 2> foo {{C('1'), C('2')}};
 int x;
 constexpr C(char c) : x(c) {} // please use a mem-initializer-list
};

With errors similar to (Clang 3.3 SVN here):

/usr/include/c++/v1/array:136:16: error: field has incomplete type 'value_type'
      (aka 'C')
    value_type __elems_[_Size > 0 ? _Size : 1];
               ^
t.cpp:5:36: note: in instantiation of template class 'std::__1::array'
      requested here
 static constexpr std::array<C, 2> foo {{C('1'), C('2')}};
                                   ^
t.cpp:3:7: note: definition of 'C' is not complete until the closing '}'
class C {
      ^

Upvotes: 3

Related Questions