Почему эта "неопределенная внешняя переменная" не приводит к ошибке компоновщика в C++17?
Я скомпилировал и запустил следующую программу в компиляторе 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;
}
Почему компилятор не выдает ошибку компоновщика?
4 ответа
Потому что переменная не используется odr. У тебя есть constexpr if
там, который всегда отбрасывает ветку, которая могла бы его использовать.
Одна из точек constexpr if
в том, что отброшенная ветвь не должна даже компилироваться, только должна быть правильно сформирована. Вот как мы можем размещать вызовы несуществующих функций-членов в отброшенной ветви.
В вашем случае переменная используется только в отброшенных выражениях. Однако, даже если мы игнорируем этот факт, спецификация языка C++ по-прежнему явно заявляет, что для пропущенных определений не требуется никакой диагностики
3.2 Правило одного определения
4 Каждая программа должна содержать ровно одно определение каждой не встроенной функции или переменной, которая используется в этой программе с помощью odr, за исключением исключенного оператора (6.4.1); Диагностика не требуется.
Спецификация языка понимает, что оптимизирующий компилятор может быть достаточно умен, чтобы исключить любое использование переменной odr. В этом случае было бы чрезмерным и ненужным требовать, чтобы реализация выявляла и сообщала о потенциальных нарушениях ODR.
Поскольку компилятор выдает ошибки компилятора, компоновщик выдаст ошибки компоновщика...
Нет, серьезно:
if constexpr (true)
всегда имеет значение true, поэтому компилятор игнорирует остальную часть предложения if, потому что оно никогда не достигается. Так i
никогда не используется на самом деле.
На этот вопрос уже был дан ответ, но если вам интересно, на cppreference.com приведен именно такой пример для constexpr, если:
Constexpr If
Утверждение, которое начинается с
if constexpr
известен как оператор constexpr if.В выражении constexpr if значение condition должно быть контекстно-преобразованным константным выражением типа bool. Если значение равно true, то оператор-ложь отбрасывается (если присутствует), в противном случае оператор-истина отбрасывается.
[...]
Отброшенный оператор может использовать переменную, которая не определена:
extern int x; // no definition of x required
int f() {
if constexpr (true)
return 0;
else if (x)
return x;
else
return -x;
}