Я проверил GCC buglist и Clang buglist и пока ничего не вижу.
Эта ссылка Wandbox показывает код С++ 11/С++ 14, выполняющий decltype(x) и decltype((x)) для различных типов x, захваченный лямбдами. GCC и Clang дают разные ответы на этот код. Какие из них, если они есть, верны?
Здесь оскорбительный фрагмент:
// inside main()
int i = 42;
int &j = i;
[j=j](){
static_assert(std::is_same<decltype(j), GCC(const) int>::value,""); // A
static_assert(std::is_same<decltype((j)), const int&>::value,""); // B
}();
[=](){
static_assert(std::is_same<decltype(j), int&>::value,""); // C
static_assert(std::is_same<decltype((j)), CLANG(const) int&>::value,""); // D
}();
где:
#ifdef __clang__
#define CLANG(x) x
#define GCC(x)
#else
#define GCC(x) x
#define CLANG(x)
#endif
Я считаю, что в обоих случаях вещь, которая фактически захвачена (*) является (не const) int, инициализированной копией значения j (то есть, i). Поскольку лямбда не отмечена mutable, ее operator() будет функцией члена const. Исходя из этих предпосылок, позвольте продолжить...
В строке // A GCC сообщает мне, что decltype явно init-capture j равен const int, когда я почти уверен, что он должен быть int (за Clang).
В строке // B оба компилятора согласны с тем, что (j) является lvalue, относящимся к const int (поскольку лямбда не отмечена mutable); это имеет для меня смысл.
В строке // C оба компилятора согласны с тем, что j - это имя, относящееся к int&, объявленному в строке 2. Это является следствием 5.1.2 [expr.prim.lambda]/19, а точнее, является следствием действия-thing-that-when-when-this-clause-is-not-being. Внутри [=] лямбда имя j относится к j во внешней области видимости, но выражение (j) относится к (j), которое существовало бы, если бы j должны были быть захвачены. Я не совсем понимаю, как это работает или почему это желательно, но вот оно. Я готов указать, что это не ошибка в компиляторе.
В строке // D Клэнг говорит мне, что (j) является lvalue, относящимся к const int, тогда как GCC сообщает мне, что это lvalue, ссылаясь на неконстантный int. Я почти уверен, что Кланг прав, и GCC ошибается; decltype((j)) должен быть одинаковым, будет ли j зафиксирован неявно или явно.
Итак:
- Являются ли мои объяснения правильными (в соответствии со стандартом)?
- Изменяется ли правильный ответ между С++ 11 и С++ 14 (и С++ 1z)?
- Являются ли
// Aи// Dобе ошибки в GCC? - Были ли уже зарегистрированы эти ошибки?
(*) - на самом деле ничто не технически захватывается второй лямбда, потому что оно не использует j в любом оцениваемом контексте. Поэтому строки // A и // C дают разные ответы. Но я не знаю никакой красивой терминологии для того, что-бы-быть-сделано-до-j, поэтому я просто говорю "захвачен".