Лямбда-захват объекта constexpr

GCC 4.7.2 компилирует это:

constexpr int i = 5;
[]{ std::integral_constant< int, i >(); }; // nonstandard: i not captured

но не это

constexpr int i = 5;
[&i]{ std::integral_constant< int, i >(); }; // GCC says i not constexpr

Последний пример кажется мне правильным, согласно C ++ 11 §5.1.2 / 15:

Сущность захватывается ссылкой, если она неявно или явно захвачена, но не захвачена копией. Не определено, объявлены ли дополнительные безымянные нестатические члены-данные в типе закрытия для объектов, захваченных ссылкой.

Похоже захваченный объект i внутри лямбда относится к переменной во вложенной области видимости, которая constexprне просто const ссылка.

Стандарт прямо говорит, что использование захвата по значению преобразуется в использование соответствующего члена лямбда-объекта. И я думаю, что 5.1.2 намекает на то, что моя интерпретация верна.

Есть ли что-нибудь, что прямо говорит о том, относится ли захват по ссылке к объекту в пределах объема или к ссылке?

19

Решение

Второй Шаблон-аргумент в std::integral_constant< int, i > для Шаблон-параметр из не типа форма, а именно целочисленный тип или тип перечисления (14.3.2p1 bullet 1) и поэтому должно быть преобразованным константным выражением типа int,

В лямбда-выражение, неявный захват происходит, когда сущность используется в составном операторе (5.1.2p11); использование преобразованного константного выражения в явной реализации шаблона не является odr-use (3.2p3), поэтому первый пример верен.

Во втором примере я думаю, что gcc неверен, чтобы отклонить его; 5.1.2p17 в записке говорится, что:

ID-выражение это не использование odr относится к исходной сущности, никогда к члену типа замыкания.

Хотя в параграфе в целом обсуждается захват копией, нет никаких оснований не применять это правило и к захвату по ссылке. Неудивительно, что стандарт неясен в этом отношении; на самом деле нет причин фиксировать сущность, которую можно использовать в преобразованном константном выражении по ссылке.

10

Другие решения

Во-первых, я могу подтвердить ваши наблюдения с помощью gcc 4.6.3 и clang 3.0 в Ubuntu 12.04.

У меня нет стандарта C ++ 11 (только черновик), поэтому я не могу это комментировать. Но посмотрите на, насколько я понимаю, эквивалентные утверждения

constexpr int i = 5;
const int &j = i;
std::integral_constant<int, j>();

Ни gcc, ни clang не компилируют это, потому что j не является «интегральной константой».

0