2012-01-26 4 views
6

В этом answer Я дал, имел смысл использовать this и атрибут класса _arg в обратном типе возврата как часть выражения decltype. Можно обойтись без, но неудобно.Используя это и атрибуты в возвращаемых типах возвращаемых функций члена?

Ни как clang 3.0 (см. Ниже), ни gcc 4.5.2 принял его.

#include <iostream> 

class MyClass { 
public: 
    MyClass(int i): _arg(i) {} 

    template <typename F> 
    auto apply(F& f) -> decltype(f(_arg)) { 
    return f(_arg); 
    } 

    template <typename F> 
    auto apply(F& f) -> decltype(f(*this, _arg)) { 
    return f(*this, _arg); 
    } 

private: 
    int _arg; 
}; 

struct Id { 
    template <typename V> 
    V operator()(V v) const { return v; } 
}; 

struct ComplexId { 
    template <typename C, typename V> 
    V operator()(C const&, V v) { return v + 1; } 
}; 

int main() { 
    Id id; ComplexId complex; 

    MyClass c(0); 

    std::cout << c.apply(id) << " " << c.apply(complex) << "\n"; 
} 

лязг 3,0 говорит:

$ clang++ -std=c++11 -Weverything test.cpp 
test.cpp:8:38: error: use of undeclared identifier '_arg' 
     auto apply(F& f) -> decltype(f(_arg)) { 
            ^
test.cpp:8:45: error: type name requires a specifier or qualifier 
     auto apply(F& f) -> decltype(f(_arg)) { 
              ^
test.cpp:8:45: error: C++ requires a type specifier for all declarations 
     auto apply(F& f) -> decltype(f(_arg)) { 
          ~~~~~~~~  ^
test.cpp:8:7: error: 'auto' return without trailing return type 
     auto apply(F& f) -> decltype(f(_arg)) { 
    ^
test.cpp:13:39: error: invalid use of 'this' outside of a nonstatic member function 
     auto apply(F& f) -> decltype(f(*this, _arg)) { 
            ^
test.cpp:13:52: error: type name requires a specifier or qualifier 
     auto apply(F& f) -> decltype(f(*this, _arg)) { 
               ^
test.cpp:13:52: error: C++ requires a type specifier for all declarations 
     auto apply(F& f) -> decltype(f(*this, _arg)) { 
          ~~~~~~~~    ^
test.cpp:13:7: error: 'auto' return without trailing return type 
     auto apply(F& f) -> decltype(f(*this, _arg)) { 
    ^
8 errors generated. 

Hum ... не так велика.

Однако поддержка C++ 11 в большинстве компиляторов является хакерством, и я не мог найти конкретных ограничений, упомянутых в стандарте (n3290).

В комментариях, Xeo предположил, что это могло бы быть дефект в стандарте ...

Итак, это разрешено или нет?

Бонус: и выполняете ли последние версии поддержки clang/gcc?

+0

Clang 3.1 HEAD извергает те же ошибки. – Xeo

+0

Аналогичные ошибки в GCC 4.7. –

+0

Btw, я только что нашел [этот интересный, похожий вопрос] (http://stackoverflow.com/q/7255379/500104). Кроме того, с предложением @Johannes объявить член upfront, я получаю сообщение об ошибке '' '' '' 'в конце возвращаемого типа, а не о' _arg' больше с Clang 3.1 HEAD. – Xeo

ответ

9

Я забыл. Это был a defect at some point, но в итоге resolved and voted into the FDIS.

§5.1.1 [expr.prim.general]

Если декларация объявляет функции-члена или члена шаблона функции класса X, выражение this является prvalue типа «указатель на резюме-спецификатор-слX» между опциональный CV-Qualifer-сл и конец функции четкости, член-описателя или описателя.

Как таковые, Clang и GCC просто не реализуют его правильно.

struct X{ 
    // 'this' exists between the | markers 
    void f() const volatile | { 
    } | 
    auto g() const volatile | -> void { 
    } | 
}; 
1

Я не знаю, что вы пишете это законно, но есть и другие способы достижения того, что вы хотите:

template <typename F> 
    auto apply(F& f) -> decltype(f(*(MyClass*)0, (int)0)) { 
    return f(*this, _arg); 
    } 

Или:

template <typename F> 
    typename std::result_of<F(MyClass,int)>::type apply(F& f) { 
    return f(*this, _arg); 
    } 
+0

В ответе, к которому я привязан, дается более подробная форма, которая работает. Обратите внимание, что существование 'std :: declval ' разрешено в неоцененных контекстах, трюк с нулевым указателем не нужен :) –

5

Ваш код is Недопустимый C++ 11, потому что класс не считается полным в возвращаемом типе функции-члена. Вы можете получить доступ только к тем, кто ранее был объявлен. Как так

class MyClass { 
private: 
    int _arg; 

public: 
    MyClass(int i): _arg(i) {} 

    template <typename F> 
    auto apply(F& f) -> decltype(f(_arg)) { 
    return f(_arg); 
    } 

    template <typename F> 
    auto apply(F& f) -> decltype(f(*this, _arg)) { 
    return f(*this, _arg); 
    } 
}; 

Modulo, что да, используя this действует в C++ 11 в возвращаемый тип трейлинг.

+0

А, это интересно. Я не думал об этом, но это имеет смысл, поскольку, если я правильно помню, то же самое относится к типам (т.е. они должны быть объявлены до использования даже в классах). –

+0

Нет внутренних функциональных тел члена класс считается полным. поэтому видны даже те элементы, которые объявлены позже. –

+0

Я специально думал об этом [http://ideone.com/T1ZS8): 'struct A {type foo(); typedef int type; }; '. Всегда прослушивал меня как * старый стиль * разбор: x –

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