2016-09-09 5 views
9

Наличие лямбды в индексе оператора, похоже, не работает для g ++ и clang.лямбда внутри индексатора итератора

Является ли это ошибкой реализации или «несчастливым» правилом в стандарте C++?

Пример:

class A 
{ 
    public: 
     template<typename T> void operator[](T) {} 
     template<typename T> void operator()(T) {} 
}; 

int main() 
{ 
    A a; 
    a[ [](){} ]; // did not compiler: see error message 
    a([](){}); // works as expected 
} 

Ошибка:

main.cpp:13:6: error: two consecutive '[' shall only introduce an attribute before '[' token 
    a[ [](){} ]; 
    ^ 
main.cpp:13:15: error: expected primary-expression before ']' token 
    a[ [](){} ]; 

Я знаю, что атрибуты начинается с "[[", но мне интересно, что "[[" (с одним или более пробелов), также работает как:

void func(int x [ [gnu::unused] ]) {} // compiles fine! :-(

ответ

4

Это описано в [dcl.attr.grammar]. Имея два последовательных [ является атрибутом, так что вам придется обернуть в скобках или сделать что-то еще, чтобы сделать ваше намерение ясно:

Two consecutive left square bracket tokens shall appear only when introducing an attribute-specifier or within the balanced-token-seq of an attribute-argument-clause. [ 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. 
    int i [[vendor::attr([[]])]]; // well-formed implementation-defined attribute. 
} 

—end example ]

+1

И есть ли «последовательное» значение с дополнительными пробелами или без них? – Klaus

+1

@Klaus C++ не является чувствительным к пробелу. '>>' было исключением в том, что считалось маркером, но нет '[[' token. – Barry

+1

Вчера я узнал, что 'template <> double B :: var = 1.123; 'недопустим, но' template <> double B :: var = 1.123; 'работает. Только пробел ... :-) – Klaus

6

Вы должны вставить лямбда в круглые скобки. В противном случае компилятор рассматривает два [[ как введение атрибута.

Аналогичная проблема может возникнуть при использовании оператора delete. Например, вы должны написать

delete ([] { return (new int()); }()); 

или

delete [] ([] { return (new int[10]); }()); 

что вы должны заключить в скобки лямбда.

+0

Великого видеть эти любопытные примеры из других контекстов. Спасибо – Klaus

1

Вы можете обернуть аргумент со скобками

a[ ([](){}) ]; 
+0

Теперь идея, как здесь была первая :-): Приятно видеть обходное решение. Но кто-нибудь задумал это по стандарту? Исправление начала атрибутов в '[[' удалит эту проблему. Вот почему я спросил, не нарушена ли реализация или «неудачный» стандарт. – Klaus

Смежные вопросы