Почему статическая переменная-член constexpr не может быть передана в функцию?
Следующий код производит undefined reference to 'Test::color'
,
#include <iostream>
struct Color{
int r,g,b;
};
void printColor(Color color) {
//printing color
}
class Test {
static constexpr Color color = {242,34,4};
public:
void print(){
printColor(color);
}
};
int main() {
Test test;
test.print();
return 0;
}
Почему этот код вызывает вышеуказанную ошибку и как ее лучше избежать, учитывая, что я хочу использовать последнюю версию стандарта C++17?
Должен ли я определять статическую переменную-член, так же, как это было необходимо в более ранних версиях стандарта (см. Первый ответ здесь: неопределенная ссылка на статический constexpr char []), или я должен просто создать новый Color
структура как видно ниже?
printColor(Color{color.r, color.g, color.b});
Редактировать: я использую CLion на Ubuntu 16.04, который, насколько я мог узнать, использует g++ 5.4 для компиляции. Я установил его на использование C++ 17 и все еще получаю ту же ошибку. Ошибка присутствует только когда color
передается в функцию.
2 ответа
Проблема не была ни в самом коде, ни в используемом стандарте. Компилятор CLion по умолчанию не полностью поддерживает C++17, поэтому он показал странное поведение, которое он может скомпилировать static constexpr
переменные-члены, но только до тех пор, пока они не были переданы в функции.
После обновления до последней версии компилятора я смог успешно выполнить код без каких-либо изменений.
Спасибо за ваш вклад.
Это связано с тем, что до C++17 вам приходилось специально определять статическую переменную вне класса:
class Test {
/* ... etc etc ... */
}
const constexpr Color Test::color;
Непротиворечивость статического члена не позволяет вам отказаться от этого требования явного определения.
С C++17 вам больше не нужно явно определять статические члены. Они неявно являются "встроенными" переменными, которые автоматически определяются в определенный момент, и только один раз для двоичного файла, без необходимости заботиться об этом. Смотрите здесь для длинного предложения этой функции.
Обратите внимание, что определение должно появляться только в одной единице перевода (поэтому, вероятно, не в заголовке с классом Test, который часто включается).