Почему эта переменная undefined extern "не приводит к ошибке компоновщика в С++ 17?
Я скомпилировал и запустил следующую программу в компиляторе С++ 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;
}
Почему компилятор не дает ошибку компоновщика?
Ответы
Ответ 1
Поскольку переменная не используется odr. У вас есть constexpr if
, который всегда отбрасывает ветвь, которая может ее использовать.
Одна из точек constexpr if
заключается в том, что отбрасываемая ветвь даже не компилируется, она должна быть хорошо сформирована. Это то, как мы можем размещать вызовы несуществующих функций-членов в отброшенной ветки.
Ответ 2
В вашем случае переменная используется только в отброшенных операторах. Однако, даже если мы игнорируем этот факт, спецификация языка С++ все еще явно заявляет, что для отсутствующих определений не требуется диагностика
3.2 Одно правило определения
4 Каждая программа должна содержать ровно одно определение каждой не-встроенной функции или переменной, которая используется в этой программе вне отбрасываемого оператора (6.4.1); не требуется диагностика.
Спецификация языка понимает, что оптимизирующий компилятор может быть достаточно умным, чтобы исключить все odr-виды использования переменной. В этом случае было бы чрезмерным и излишним требовать, чтобы внедрение выявляло и сообщало о возможных нарушениях в рамках ODR.
Ответ 3
Поскольку компилятор создает ошибки компилятора, компоновщик даст ошибки компоновщика...
Нет, серьезно:
if constexpr (true)
всегда истинно, поэтому компилятор игнорирует остальную часть if-предложения, потому что он никогда не достигается. Поэтому i
никогда не используется.
Ответ 4
На это ответили alrady, но если вам интересно, cppreference.com имеет именно этот пример для constexpr, если:
Constexpr Если
Оператор, начинающийся с 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;
}