2017-02-19 36 views
3

У меня возникают некоторые трудности с атрибутами static constexpr: он работает со встроенными типами, с enum class членами, но когда я пытаюсь сделать это со статически инициализированным интегральным массивом, он не работает при linking undefined reference to S::a внутри main.C++ 14 статический массив элементов constexpr не работает при связывании

То есть с clang 3.9 или g ++ 6.3 и ld 2.27.90; и все это с -std=c++14.

Вот самый быстрый сниппет воспроизвести это:

struct S 
{ 
    static constexpr int a[5] = {0}; 
}; 


int main() 
{ 
    S s{}; 
    [[gnu::unused]] int b = s.a[0]; // force S stuff to be emitted 
    return 0; 
} 

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

+0

Необходимо определить ваш объект; в области пространства имен: 'constexpr int S :: a [5];' – ildjarn

+0

@ildjarn спасибо! но знаете ли вы, почему я должен делать это для массивов, но не для других вещей, таких как простые интегральные типы? – suut

ответ

5

Рассмотрим этот код:

enum class E { foo, bar }; 
struct S 
{ 
    static constexpr int a[5] = {0}; 
    static constexpr int b = 42; 
    static constexpr E e = foo; 
}; 

Все выше декларации, и не определения. Для каждого из них, вы должны предоставить определение:

int S::a[5]; 
int S::b; 
E S::e; 

он работает со встроенными типами, с перечисляемых членов класса

Это работает более или менее случайно. В частности, это работает, потому что у вас никогда не было контекста, где принимается адрес этой переменной (никогда не используйте ODR-переменную).

Часто я вижу, как люди добавляют невинно выглядящий призыв к std::max и неожиданно обнаруживают, что они не предоставили определения. То есть:

int main() 
{ 
    printf("%d\n", S::b);  // works fine 
    int x = std::max(1, S::b); // fails to link in non-optimized build. 
}