2012-01-26 8 views
6

En este answer di, tenía sentido utilizar this y el atributo de la clase _arg en el tipo de retorno de arrastre como parte de la expresión decltype. Es posible prescindir, pero inconveniente.¿Usando esto y atributos en la función de miembro detrás de los tipos de devolución?

Ni el clang 3.0 (véase a continuación) ni el gcc 4.5.2 lo aceptaron sin embargo.

#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"; 
} 

sonido metálico 3.0 dice:

$ 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 ... no es tan grande.

Sin embargo, el soporte de C++ 11 es hacky en el mejor de los casos en la mayoría de los compiladores y no pude encontrar restricciones específicas mencionadas en el Estándar (n3290).

En los comentarios, Xeo sugirió que podría haber sido un defecto en la Norma ...

Por lo tanto, se esta permitido o no?

Bonificación: y ¿hay versiones más recientes de clang/gcc compatibles?

+0

Clang 3.1 HEAD arroja los mismos errores. – Xeo

+0

Errores similares en GCC 4.7. –

+0

Por cierto, acabo de encontrar [esta pregunta interesante y similar] (http://stackoverflow.com/q/7255379/500104). Además, con la sugerencia de @Johannes de declarar al miembro por adelantado, solo obtengo un error sobre 'this' en el tipo de devolución final, no sobre' _arg' con Clang 3.1 HEAD. – Xeo

Respuesta

9

I misremembered. Era a defect at some point, pero finalmente fue resolved and voted into the FDIS.

§5.1.1 [expr.prim.general]

Si una declaración declara una plantilla de función función miembro o miembro de una clase X, la expresión this es una prvalue del tipo “puntero a cv-calificador-ssX” entre el opcional cv-calificador-seq y el final de la función definición, miembro-declarador, o declarador.

Como tal, Clang y GCC simplemente aún no lo implementan correctamente.

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

No sé si lo que escribo es legal, pero hay algunas otras maneras de lograr lo que quiere:

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

O:

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

En la respuesta a la que me he vinculado, se da una forma más detallada que funciona. Tenga en cuenta la existencia de 'std :: declval ' permitido en contextos no evaluados, el truco del puntero nulo no es necesario :) –

5

Su código es C++ 11 no válido, porque la clase no se considera completa en el tipo de devolución de una función miembro. Solo puedes acceder a miembros que hayan sido declarados previamente. Al igual que

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 de que, sí utilizando this es válida en C++ 11 en un tipo de retorno de arrastre.

+0

Ah, eso es interesante. No había pensado en ello, pero tiene sentido ya que, si no recuerdo mal, lo mismo se aplica a los tipos (es decir, deben declararse antes de su uso, incluso en las clases). –

+0

No hay cuerpos de función miembro internos, la clase se considera completa. por lo que incluso los tipos de miembros declarados más tarde son visibles. –

+0

Estaba pensando específicamente en [esto] (http://ideone.com/T1ZS8): 'struct A {type foo(); typedef int type; }; '. Siempre me molestaba como siendo * old-style * parsing: x –

Cuestiones relacionadas