Я проверил 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
, поэтому я просто говорю "захвачен".