файлах Почему эта «неопределенная внешняя переменная» не приводит к ошибке компоновщика в C++ 17?




статическая переменная c++ (4)

Я компилировал и запускал следующую программу в компиляторе C ++ 17 (Coliru). В программе я объявлял extern переменную, но не определял ее. Однако компилятор не дает ошибку компоновщика .

#include <iostream>

extern int i; // Only declaration

int func() 
{
    if constexpr (true)
        return 0;
    else if (i)
        return i;
    else
        return -1;
}

int main() 
{
    int ret = func();
    std::cout<<"Ret : "<<ret<<std::endl;
}

Почему компилятор не дает ошибку компоновщика?


В вашем случае переменная используется только в отброшенных операторах. Однако, даже если мы игнорируем этот факт, спецификация языка C ++ все еще явно заявляет, что для отсутствующих определений не требуется никакой диагностики

3.2. Правило с одним определением

4 Каждая программа должна содержать ровно одно определение каждой не-встроенной функции или переменной, которая является odr-используемой в этой программе вне отбрасываемого оператора (6.4.1); не требуется диагностика .

Спецификация языка понимает, что оптимизирующий компилятор может быть достаточно умным, чтобы исключить все odr-виды использования переменной. В этом случае было бы чрезмерным и излишним требовать, чтобы внедрение выявляло и сообщало о возможных нарушениях ОДР.


Поскольку переменная не используется odr. У вас есть constexpr if всегда отбрасывает ветку, которая может ее использовать.

Одна из точек constexpr if заключается в том, что отброшенная ветвь не нуждается даже в компиляции, только должна быть хорошо сформирована. Вот как мы можем размещать вызовы несуществующих функций-членов в отброшенной ветви.


На это ответили cppreference.com , но если вам интересно, cppreference.com имеет именно этот пример для constexpr, если :

Constexpr If

Оператор, начинающийся с if constexpr , известен как оператор constexpr if .

В выражении constexpr if значение условия должно быть контекстно-преобразованным константным выражением типа bool. Если значение истинно, то выражение-false отбрасывается (если присутствует), в противном случае оператор-true отбрасывается.
[...]
Отброшенный оператор может odr-use переменную, которая не определена:

extern int x; // no definition of x required
int f() {
if constexpr (true)
    return 0;
else if (x)
    return x;
else
    return -x;
}

Поскольку компилятор создает ошибки компилятора, компоновщик даст ошибки компоновщика ...

Нет, серьезно:

if constexpr (true)

всегда верно, поэтому компилятор игнорирует остальную часть if-предложения, потому что он никогда не достигается. Поэтому i никогда не использую на самом деле.





if-constexpr