24

GCC 4.7.2 compiles this:

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

but not this:

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

The latter example appears correct to me, according to C++11 §5.1.2/15:

An entity is captured by reference if it is implicitly or explicitly captured but not captured by copy. It is unspecified whether additional unnamed non-static data members are declared in the closure type for entities captured by reference.

It seems the captured object i inside the lambda refers to the variable in the enclosing scope, which is constexpr, not merely a const reference.

The standard explicitly says that the use of a by-value capture is transformed into a use of the corresponding member of the lambda object. And I think that 5.1.2 hints that my interpretation is correct.

Is there anything that explicitly says that whether a capture by reference refers to the object in the enclosing scope or a reference?

2
  • 2
    What happens if you use clang? Commented Nov 20, 2012 at 8:15
  • 1
    @RichardJ.RossIII Clang compiles both cases. Commented Nov 20, 2012 at 8:19

2 Answers 2

12

The second template-argument to std::integral_constant< int, i > is for a template-parameter of non-type form, specifically of integral or enumeration type (14.3.2p1 bullet 1) and so must be a converted constant expression of type int.

In a lambda-expression, implicit capture occurs when an entity is odr-used in the compound statement (5.1.2p11); use of a converted constant expression in an explicit template instantiation is not odr-use (3.2p3), so the first example is valid.

In the second example, I think gcc is incorrect to reject it; 5.1.2p17 says in a note that:

An id-expression that is not an odr-use refers to the original entity, never to a member of the closure type.

Although the paragraph as a whole is discussing capture by copy, there's no reason not to apply this rule to capture by reference as well. It's unsurprising that the standard is unclear on this; there's really no reason to capture an entity that can be used in a converted constant expression by reference.

Sign up to request clarification or add additional context in comments.

3 Comments

Hmm, I was thinking gcc might be correct in rejecting the second example. From 5.1.2p12: An entity captured by a lambda-expression is odr-used (3.2) in the scope containing the lambda-expression. I read that as meaning the explicit capture, i.e. [&i] means it is odr-used. I could be wrong though.
@JesseGood that's saying that i is odr-used in the enclosing scope, not in the compound statement.
Yes, perhaps you are right. I guess explicit capture does not warrant odr-use in the lambda expression. Although that area could be more clear.
0

First, I can confirm your observation with gcc 4.6.3 and clang 3.0 on Ubuntu 12.04.

I don't have the C++11 standard (only draft), so I cannot comment on that. But look at the, from my understanding, equivalent statements

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

Neither gcc, nor clang compiles this, because j is not an "integral constant".

2 Comments

Drafts are released regularly; effectively they fix errata in the standard as the committee is still "fixing bugs" not "adding features." The latest is N3485. The point of the question is to ask whether a declaration such as j is guaranteed not to be introduced.
@Potatoswatter Thanks for this info. Then I must "update" my N3242 draft.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.