c++lambdavisual-c++-2013

Left bracket not matched correctly while using lambda inside brackets, inside template function


Using Visual C++ 2013, the following code produces a weird compile error:

/// header.h
class Test
{
public:
    template <typename Func>
    void operator[](Func f)
    {
        f();
    }
};

template <typename T>
void funct()
{
    Test t;
    t[[](){; }];    // line 16 // The same error with t[ ([](){; }) ];
}

/// main.cpp
int main()
{
    funct<int>();
    // funct();
}

Errors:

1>c:\path\to\header.h(16): error C2958: the left bracket '[' found at 'e:\path\to\header.h(16)' was not matched correctly
1>c:\path\to\header.h(16): error C2059: syntax error : ']'
1>c:\path\to\header.h(17): error C2059: syntax error : '}'
1>c:\path\to\header.h(17): error C2143: syntax error : missing ';' before '}'


This error does not happen when the lambda function body doesn't have any statements:

template <typename T>
void funct()
{
    Test t;
    t[[](){ }];    // line 16 // No semicolon - No statement - No errors
}


Or when the function is not template:

// Ordinary function - No errors
void funct()
{
    Test t;
    t[[](){; }];    // line 16
}


I think I have found a bug in this compiler. However, if anyone knows a way to write this without errors and without using a variable to hold the lambda function, that would be great.


Solution

  • VC++ correctly rejects this code, but for the wrong reasons - it's a bug. It's ill-formed according to [dcl.attr.grammar]/6:

    Two consecutive left square bracket tokens shall appear only when introducing an attribute-specifier. [ Note: If two consecutive left square brackets appear where an attribute-specifier is not allowed, the program is ill-formed even if the brackets match an alternative grammar production. ā€” end note ] [ Example:

    int p[10];
    void f() {
        int x = 42, y[5];
        int(p[[x] { return x; }()]); // error: invalid attribute on a nested
                                     // declarator-id and not a 
                                     // function-style cast of an element of p.
    
        y[[] { return 2; }()] = 2; // error even though attributes are not allowed
                                   // in this context.
    }
    

    ā€” end example ]

    So try enclosing the lambda-expression in two parantheses as follows.

    t[ ([](){; }) ];
    

    Or write

    auto&& closure = [](){; };
    t[closure]; // move here if correct value category is desired