2012-01-26 7 views
6

In questo answer ho dato, ha avuto senso utilizzare this e l'attributo della classe _arg nel tipo di ritorno finale come parte dell'espressione decltype. Si può fare a meno, ma è scomodo.Utilizzando questo e gli attributi nella funzione membro trailing tipi di ritorno?

Né clang 3.0 (vedere di seguito) né gcc 4.5.2 tuttavia accettato.

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

clang 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 ... non così grande.

Tuttavia, il supporto di C++ 11 è hacky nella migliore delle ipotesi nella maggior parte dei compilatori e non sono riuscito a trovare restrizioni specifiche menzionate nello standard (n3290).

Nei commenti, Xeo suggerito che avrebbe potuto essere un difetto nel standard ...

Quindi, è questo permessi o meno?

Bonus: e le versioni più recenti di clang/gcc supportano questo?

+0

Clang 3.1 HEAD rilascia gli stessi errori. – Xeo

+0

Errori simili su GCC 4.7. –

+0

Btw, ho appena trovato [questa interessante domanda simile] (http://stackoverflow.com/q/7255379/500104). Inoltre, con il suggerimento di @Johannes di dichiarare il membro in anticipo, ricevo solo un errore su "this" nel tipo di ritorno finale, non più su "_arg" con Clang 3.1 HEAD. – Xeo

risposta

9

I misremembered. Era a defect at some point, ma alla fine era resolved and voted into the FDIS.

§5.1.1 [expr.prim.general]

Se una dichiarazione dichiara una funzione membro o di un membro modello di funzione di una classe X, l'espressione this è un prvalue di tipo “puntatore a cv-qualificatore-SeqX” tra il optional cv-qualifer-seq e la fine della funzione definizione, membro dichiaratore o dichiaratore.

In questo modo, Clang e GCC non lo implementano ancora correttamente.

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

Non so se quello che scrivi è legale, ma ci sono altri modi per raggiungere ciò che si desidera:

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

Oppure:

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

Nella risposta a cui mi sono collegato, viene fornita una forma più dettagliata che funziona. Si noti l'esistenza di 'std :: declval ' consentito in contesti non valutati, il trucco del puntatore nullo non è necessario :) –

5

Il codice è C++ 11 non valido, poiché la classe non è considerata completa nel tipo restituito di una funzione membro. È possibile accedere solo ai membri che sono stati precedentemente dichiarati. Come così

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 che, sì utilizzando this è valido in C++ 11 in un tipo di ritorno finale.

+0

Ah, è interessante. Non ci avevo pensato, ma ha senso poiché, se ricordo bene, lo stesso vale per i tipi (cioè devono essere dichiarati prima dell'uso anche nelle classi). –

+0

Nessun membro della funzione membro interno la classe è considerata completa. quindi anche i tipi di membri dichiarati in seguito sono visibili. –

+0

Stavo pensando specificamente a [questo] (http://ideone.com/T1ZS8): 'struct A {type foo(); typedef int type; }; '. Mi ha sempre infastidito come * parsing * vecchio stile: x –

Problemi correlati