Еще одно несоответствие clang/gcc относительно использования ODR?
Почему этот код компилируется с GCC (4.9 и 5+), а не с clang (3.5-3.9)?
void test(const int&) { }
int main() {
const int x = 42;
auto f = []{ test(x); };
}
У меня есть некоторое смутное представление о том, что расхождение связано с использованием ODR (правила одного определения), но я не понимаю этого достаточно хорошо, чтобы понять, что здесь происходит.2 ответа:
x
используется odr, поскольку он привязан к ссылке (параметруtest
). Поэтому он должен быть захвачен ( [expr.подтянутый.лямбда]/13):Если лямбда-выражение или экземпляр вызова функции шаблон оператора универсального лямбда Усо-использует ([основная.защита.odr])
this
или переменная с автоматической длительностью хранения из области ее достижения, эта сущность должна быть захвачена лямбда-выражением .Нарушения этого правила, как и все другие правила в стандарте, которые не говорят "не требуется диагностика" или "неопределенное поведение", требуют диагностики.
GCC, к сожалению, выполняет постоянное сворачивание слишком рано, прежде чем он сможет сказать, является ли это использование odr или нет. Это может привести к проблемам , таким как
[&]()->const int & { return x; }
возврат висящей ссылки.
У T. C. правильный диагноз, вот более четкий фрагмент юридического кодекса, где clang делает правильные вещи, а gcc-нет:
#include <iostream> void test(const int&a) { std::cout << "in test() -- " << &a << "\n"; } int main() { const int x = 42; std::cout << "in main() -- " << &x << "\n"; auto f = [&]{ test(x); }; f(); }
Gcc печатает разные адреса для переменной capture-by-reference, чем оригинал!