Почему здесь используется переменная const stati c odr? - PullRequest
3 голосов
/ 07 мая 2020

Рассмотрим следующий код:

class Test {
    public:
        static const int VALUE = 100;
};

std::tuple<int> foo(std::tuple<int> value) {
    return value;
}

int main()
{
    auto t = std::make_tuple(Test::VALUE); // This compiles fine
    auto t1 = foo(std::make_tuple(Test::VALUE)); // undefined reference to `Test::VALUE' linker error
}

Согласно другому вопросу ( Что значит «использовать ODR»? ) и ответу:

Простым словом odr-used означает, что что-то (переменная или функция) используется в контексте, в котором должно присутствовать определение.

В первом случае (переменная t) переменная VALUE не используется odr, потому что необходимо только ее значение. Но во втором случае почему код не компилируется? Если бы я передал t вместо rvalue (?), Код компилировался бы нормально. Чем второй случай отличается от первого и почему здесь используется VALUE odr?

Ответы [ 2 ]

3 голосов
/ 07 мая 2020

make_tuple принимает аргумент как const int& (так как это постоянное lvalue и принимает аргумент T&&), а привязка ссылки к значению является ODR-использованием.

Оба случая плохо сформированы, диагнозы c не требуются. Например, при высоких уровнях оптимизации g cc вся программа оптимизирована и ошибок компоновщика нет, а при отсутствии оптимизации оба оператора дают ошибки компоновщика.

Чтобы не использовать ODR, вы можете преобразовать его в rvalue:

    // Various ways to force the lvalue-to-rvalue conversion
    auto t = std::make_tuple(int(Test::VALUE));
    auto t1 = foo(std::make_tuple((void(), Test::VALUE)));
    auto t2 = foo(std::make_tuple(+Test::VALUE));

(так std::make_tuple принимает int&& временного)

Или вы можете сделать определение inline (проще всего с помощью constexpr):

class Test {
    public:
        static constexpr int VALUE = 100;
};
2 голосов
/ 07 мая 2020

В первом случае (переменная t) переменная VALUE не используется odr, потому что необходимо только ее значение.

Нет. Это значение необходимо, и оно используется в ODR.

Но во втором случае, почему код не компилируется?

Потому что компилятор, который вы используете, не умен достаточно, чтобы оптимизировать второй фрагмент кода. Например, обе строки отлично компилируются на gcc9.3 с -O1 .

...