7

По: constexpr static data member giving undefined reference error статические члены класса constexpr должны отвечать двум требованиям:равномерная инициализация статического члена constexpr

template <typename Tp> 
struct wrapper { 
    static constexpr Tp value{}; // 1 
}; 

template<typename Tp> 
constexpr Tp wrapper<Tp>::value; // 2 

struct foo { 
}; 

int main() { 
    auto const& x = wrapper<foo>::value; 
    (void)x;  
} 
  1. инициализируется внутри определения класса (потому что это constexpr)
  2. Defined вне (потому что он является статическим)

Если я изменю 1. на единую начальную зация

template <typename Tp> 
struct wrapper { 
    static constexpr auto value = Tp{}; // uniform initialization 
}; 

template<typename Tp> 
constexpr Tp wrapper<Tp>::value; 

компилятор жалуется на противоречивые заявления:

$ g++ prog.cc -Wall -Wextra -std=c++1z -pedantic 
prog.cc:7:31: error: conflicting declaration 'constexpr const Tp wrapper<Tp>::value' constexpr Tp wrapper<Tp>::value; 
prog.cc:3:29: note: previous declaration as 'constexpr const auto wrapper<Tp>::value' static constexpr auto value = Tp{}; 

, а также о пропавших инициализаторе:

prog.cc:7:31: error: declaration of 'constexpr const auto wrapper<Tp>::value' has no initializer 

Удаление конфликтующих 2. концы определения, как и ожидалось, с ошибкой компоновщика:

In function `main': prog.cc:(.text+0x8): undefined reference to `wrapper<foo>::value' 

Пример кода online.

Возможно ли использование законной инициализации для статических членов класса constexpr?

+0

Это что-то делать с параметром шаблона: Это работает, как ожидалось, если тип статического элемента данных не зависит от параметра шаблона, как 'статического constexpr Автозначением = int {}; ' – dyp

+0

этот класс-оболочка на самом деле является заменой шаблона переменной C++ 14 в gcc <5.0, поэтому параметр шаблона является обязательным. –

+0

Вам нужно использовать' auto'? –

ответ

0

Это может быть мое недоразумение, но я считал бы

struct wrapper { 
    static constexpr Tp value = Tp{}; 
}; 

быть примером равномерной инициализации. Действительно, первый пример кода также является равномерной инициализацией. Сам стандарт просто требует, чтобы эти статические члены constexpr были инициализированы выражением скобки или присваивания. Это, как вы уже видели, прекрасно работает.

Проблема связана с выводом типа от auto в контексте шаблона, и я подозреваю, что это ошибка реализации, хотя стандарт большой, и я мог бы что-то пропустить.

Если размер правой руки инициализации constexpr был выражением с жестким предварительным определением типа, обходным путем было бы использовать decltype, например.

template <typename Tp> 
struct wrapper { 
    static constexpr decltype(complex-init-expr) value = complex-init-expr; 
}; 

template <typename Tp> 
static constexpr decltype(complex-init-expr) wrapper<Tp>::value; 

или

template <typename Tp> 
struct wrapper { 
    typedef decltype(complex-init-expr) value_type; 
    static constexpr value_type value = complex-init-expr; 
}; 

template <typename Tp> 
static constexpr typename wrapper<Tp>::value_type wrapper<Tp>::value; 
Смежные вопросы