Следующий код создает 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?

Следует ли мне определять статическую переменную-член, как это было необходимо в более ранних версиях стандарта (см. Первый ответ здесь: Неопределенная ссылка на static constexpr char []) или мне просто нужно создать новую структуру Color, как показано ниже?

printColor(Color{color.r, color.g, color.b});

Редактировать: Я использую CLion в Ubuntu 16.04, который, насколько мне удалось выяснить, использует для компиляции g ++ 5.4. Я настроил его на использование C ++ 17, но по-прежнему получаю ту же ошибку. Ошибка присутствует только тогда, когда color передается функции.

2
user3738870 16 Сен 2018 в 17:44

2 ответа

Лучший ответ

Проблема не была ни в самом коде, ни в используемом стандарте. Компилятор по умолчанию CLion не полностью поддерживает C ++ 17, поэтому он показал странное поведение: он может компилировать переменные-члены static constexpr, но только до тех пор, пока они не передаются функциям.

После обновления до самой последней версии компилятора я смог успешно запустить код без каких-либо изменений.

Спасибо за ваш вклад.

1
user3738870 16 Сен 2018 в 19:44

Это связано с тем, что до C ++ 17 вам приходилось специально определять статическую переменную вне класса:

class Test { 
   /* ... etc etc ... */
}

const constexpr Color Test::color;

Конструктивность статического члена не позволяет вам «отказаться» от этого явного требования определения.

С C ++ 17 вам больше не нужно явно определять статические члены. Это неявно «встроенные» переменные, которые в какой-то момент определяются автоматически и только один раз для каждого двоичного файла, и вам не нужно об этом заботиться. Подробное предложение см. здесь этой функции.

Обратите внимание, что определение должно появляться только в единственной единице перевода (поэтому, вероятно, не в заголовке с классом Test, который часто включается).

3
einpoklum 18 Сен 2018 в 21:09