9

This is the simplest example I could come up with that reproduces the problem.

template<class T>
struct X
{
    static void foo()
    {
        static int z = 0;
        []{ z = 1; }();
    }
};

int main()
{
    X<int>::foo();
    return 0;
}

I've tried it with MinGW 4.6 and 4.7, also g++ 4.6 in Ubuntu and all of them give me the link error "undefined reference to `z'". So now that makes me wonder if this is even legal. VC10 has no problem with it.

It works if X is normal class instead of a template. Also, I don't think it's related to lambdas cause I get the error even if I replace the lambda with a local class.

1
  • add c++11 tag, maybe it will give you better response Commented Dec 29, 2011 at 10:54

2 Answers 2

10

g++ accepts the following, but VC++ does not:

[&z]{ z = 1; }();

Here z is being captured so g++ does not complain about an undefined reference. However:

5.1.2/10:

The identifiers in a capture-list are looked up using the usual rules for unqualified name lookup (3.4.1); each such lookup shall find a variable with automatic storage duration declared in the reaching scope of the local lambda expression.

z is not automatic storage. z can therefore not be captured. g++ behavior is therefore incorrect, and VC++ is correct.

In your code, that VC++ accepts and g++ does not:

[]{ z = 1; }();

z is accessed by VC++ as static storage, which is allowed in a lambda body. g++ apparently does not resolve the name z to the static variable declared above and therefore throws undefined reference, while it shouldn't.

tl;dr It's probably a bug in g++

Edit: It is indeed a bug and is fixed in 4.7.

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

1 Comment

Nice: it might even explain why TonyK's work around actually works, though I am not sure whether the "reference to z" would have automatic storage. Looking up 5.2.1/9, one also notes that the "reaching scope" your note refers to stops at the innermost enclosing function, thus also excluding "globals" (which do not have automatic storage duration anyway). So it seems fully intended that the capture list may only capture local variables by copy.
-1

I don't understand why it works for normal classes and not for templates. But you can get your example to work if you capture the local variable z by reference:

static void foo()
{
    static int z = 0;
    [&z]{ z = 1; }(); // Note: [&z]
}

Wikipedia has more info here.

11 Comments

Someone named @cicada posted the same answer but then she deleted it (now you're here with same answer) , don't know why did she delete it 0_o
@Mr.Anubis because I'm still trying to figure out why g++ behaves differently than VC++
@Cicada Both compilers are free to behave differently when one possibly have bug and another doesn't.
@Cicada: g++ is definitely bugged, at least as far as lambda support goes. Changing the capture list from [&z] to [&] reawakens the same error as the OP, which is at least inconsistent (regardless of the Standard). I also think (according to your answer) that VC++ is bugged since it accepts the code.
You cannot capture static variables.
|

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.