Почему статическая переменная-член 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, который часто включается).

Другие вопросы по тегам