Are function-local typedefs visible inside C++0x lambdas?
Asked Answered
S

4

12

I've run into a strange problem. The following simplified code reproduces the problem in MSVC 2010:

template <typename T>
struct dummy
{
    static T foo(void) { return T(); }
};

int main(void)
{
    typedef dummy<bool> dummy_type;
    auto x = []{ bool b = dummy_type::foo(); };
    // auto x = []{ bool b = dummy<bool>::foo(); }; // works
}

The typedef I created locally in the function doesn't seem to be visible in the lambda. If I replace the typedef with the actual type, it works as expected.

Here are some other test cases:

// crashes the compiler, credit to Tarydon
int main(void)
{
    struct dummy {};

    auto x = []{ dummy d; };
}

// works as expected
int main(void)
{
    typedef int integer;

    auto x = []{ integer i = 0; };
}

I don't have g++ available to test it, right now. Is this some strange rule in C++0x, or just a bug in the compiler?

From the results above, I'm leaning towards bug. Though the crash is definitely a bug.


For now, I have filed two bug reports.

All code snippets above should compile. The error has to do with using the scope resolution on locally defined scopes. (Spotted by dvide.)

And the crash bug has to do with... who knows. :)


Update

According to the bug reports, they have both been fixed for the next release of Visual Studio 2010. (Though this doesn't seem to be the case; VS11 perhaps.)

Serapis answered 23/1, 2010 at 5:42 Comment(3)
same thing with local namespace aliasesOuch
All three test cases compile successfully using Intel C++ Compiler 11.1.Mow
All three test cases compile successfully using g++ 4.5.Mortician
B
9

From n3000, 5.1.2/6,

The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator, but for purposes of name lookup (3.4), … the compound-statement is considered in the context of the lambda-expression.

Not surprisingly, the local type should be visible.

Boatbill answered 23/1, 2010 at 6:40 Comment(2)
Ah, i just realized that i was accidentally looking at an older draft.Quadruplicate
I'm accepting this for answering my original "is this allowed" question. :)Serapis
C
3

Function-local enums cannot be detected by lambdas either.

int main()
{   
    enum E {A, B, C};   
    auto x = [](){ int a = A; }; 
    //auto y = [](){ E a = A; }; // this will crash the compiler
}

error C3493: 'A' cannot be implicitly captured because no default capture mode has been specified

Following is a workround, problematic-maybe though.

int main()
{   
    enum E {A, B, C};   
    auto x = [=](){ int a = A; };
    // typedef E F; 
    // auto y = [=](){ F a = A; }; // this compiles ok
}
Cerberus answered 21/5, 2010 at 18:1 Comment(0)
H
2

This is not really an answer to your question, but just exploring the problem further. I was wondering if the compiler has issues dealing with types declared in an enclosing scope, so tried this out:

#include <iostream>

template <typename Func>
void do_test(Func pFunc) {
}

template <typename T>
void test_trait(void) {
   class Something { public: int foo; };

   do_test ([] (T pX) {
      Something A; A.foo = 12;
   });
}

int main(void) {
    test_trait<int> ();
}

Here, I'm just trying to create a local type in the enclosing scope and use it from within the lambda function. Not only does this not compile (with Visual Studio 2010, Beta 2) but it actually crashes the compiler with a C1001 internal error.

Haydon answered 23/1, 2010 at 6:5 Comment(1)
Strangely enough, if you make a local typedef to the local type, the crash goes away.Serapis
S
2

I have filed two bug reports.

We'll see how it goes. :)


Update

Both bugs have been marked as fixed:

We appreciate your feedback. This bug has been seen by us before and we have fixed it in next release. Thank you for using the product.

Thanks,
Ulzii Luvsanbat
Windows C++ Team

So there we go.

Serapis answered 23/1, 2010 at 6:52 Comment(8)
It doesn't seem to be related to templates but to whenever the scope resolution operator (::) is needed. A non-static foo method works as expected.Ouch
What of your namespace problem? It uses :: to get the original namespace (the working version.) Perhaps it's whenever a local definition requires ::?Serapis
Yeah that's what I meant. namespace test = foo; auto x = [](void) { return test::bar(); };Ouch
@dvide: That's ok. :) Use the back-ticks: `code goes here` becomes code goes here. (Note, you can escape with a backslash.) I'm modifying the second report to match our data.Serapis
@dvide: I have modified the "typedef-of-template" bug to the more generic "Lambda scope resolution fails with locally defined scopes.". Nice find.Serapis
It looks like neither of these is going to be resolved in the VS2010 RTM. I referenced the crash bug in an e-mail chat I had with one of the VC++ developers, along with several bugs I've reported. She said: "I currently show all of the bugs below are still active in our system. Since we are at the end of the product cycle for VS2010, these issues will be considered for a following release."Mow
@James: Ah, that's too bad. I did notice they were still present in RC, too bad they got pushed so far back. It's surprising since, at least to me, the situation in these bugs should come up quite a bit.Serapis
@James @dvide: According to the bug reports, both issues are fixed.Serapis

© 2022 - 2024 — McMap. All rights reserved.