2014-07-13 1 views
10

Comment puis-je contraindre une fonction dans une classe modélisée à renvoyer une référence à une variable membre à l'aide de auto/decltype?Utilisation de auto et decltype pour renvoyer la référence à partir de la fonction dans la classe modélisée

Voici un exemple trivial de ce que j'essaie de faire. Supposons que vous avez une classe basé sur un modèle qui stocke quelque chose dans une variable membre privée, a_ comme suit:

#include <iostream> 

template <typename T> 
class A 
{ 
private: 
    T a_; 

public: 
    A(T a) : a_(a) {} 

    // 1. Return const reference to a_ 
    const T & get() const { return a_; } 

    // 2. Return non-const reference to a_ 
    T & get() { return a_; } 
}; 

int main(int argc, char *argv[]) 
{ 
    A<int> a(3); 

    const auto & a1 = a.get(); // 1. Return const reference to a_ 
    //a1 = 4; // Shouldn't compile 
    std::cout << "Value of a = " << a.get() << std::endl; 

    auto & a2 = a.get(); // 2. Return non-const reference to a_ 
    a2 = 5; 
    std::cout << "Value of a = " << a.get() << std::endl; 

    return 0; 
} 

La sortie attendue/désirée est:

Value of a = 3 
Value of a = 5 

Mais maintenant, supposons que je veux que le compilateur pour déduire le type renvoyé par les fonctions const et non-const get() dans A<T> et je veux assurer que les deux appels renvoient références à a_.

Ma meilleure estimation est actuellement:

template <typename T> 
class A 
{ 
private: 
    T a_; 

public: 
    A(T a) : a_(a) {} 

    // 1. Return const reference to a_ 
    const auto get() const -> std::add_lvalue_reference<const decltype(a_)>::type 
    { 
    return a_; 
    } 

    // 2. Return non-const reference to a_ 
    auto get() -> std::add_lvalue_reference<decltype(a_)>::type 
    { 
    return a_; 
    } 
}; 

mais qui ne parvient pas à compiler. La première erreur donnée par GCC est:

decltype.cpp:11:29: error: expected type-specifier 
decltype.cpp:11:26: error: expected ‘;’ at end of member declaration 
decltype.cpp:11:29: error: ‘add_lvalue_reference’ in namespace ‘std’ does not name a type 

La motivation pour c'est En dehors de mon code exemple distillé, mais découle d'une tentative de réduire le nombre de paramètres d'un modèle prend quand un (ou plusieurs) de ces paramètres est utilisé uniquement pour spécifier un type de retour que le compilateur devrait (je pense) être capable de déduire par lui-même. Note: dans le monde réel, le type de retour de get() n'est pas celui de a_, mais est le type de retour de certaines fonctions f(a_) que je sais être déductibles par le compilateur. Ainsi, mon besoin d'auto/decltype dans cet exemple.

La chose qui me déconcertant est que le compilateur peut déduire le type de retour en utilisant correctement le code quasi-identique dans une classe non basé sur un modèle:

class A 
{ 
private: 
    int a_; 

public: 
    A(int a) : a_(a) {} 

    // 1. Return const reference to a_ 
    const auto get() const -> std::add_lvalue_reference<const decltype(a_)>::type 
    { 
    return a_; 
    } 

    // 2. Return non-const reference to a_ 
    auto get() -> std::add_lvalue_reference<decltype(a_)>::type 
    { 
    return a_; 
    } 
}; 

Toute aide à comprendre ce que je suis sera d'ailleurs grandement apprécié.

Détails:

Centos 6.5 
gcc (GCC) 4.7.2 20121015 (Red Hat 4.7.2-5) 
+3

vous avez besoin '' typename' – Brian

+3

const get automatique() const' Pour un type de fin-retour, vous peut seulement utiliser 'auto' avant le nom de la fonction, pas' const auto'. – dyp

+0

@dyp Etes-vous sûr? Cela fonctionne si j'ajoute 'typename' si nécessaire. – jrok

Répondre

14

Juste pour le mentionner, vous n'avez pas fait d'utiliser std::add_lvalue_reference pour obtenir le comportement que vous voulez. Cela fonctionne tout aussi bien et est plus lisible dans mon livre.

template <typename T> 
class A { 
    private: 
     T a_; 

    public: 
     A(T a) : a_(a) {} 

     const auto get() const -> const decltype(a_) & { 
      return a_; 
     } 

     auto get() -> decltype(a_) & { 
      return a_; 
     } 
}; 

int main() { 
    A<int> a(1); 
    cout << a.get() << endl; 
    a.get() = 2; 
    cout << a.get() << endl; 
} 
2

Wrap a_ dans une paire de parenthèses dans le type de retour de fuite pour obtenir le type de l'expression a_ au lieu du type de a_ variable (Live at Coliru) a déclaré supplémentaire:

// 1. Return const reference to a_ 
auto get() const -> decltype((a_)) 
{ 
    return a_; 
} 

// 2. Return non-const reference to a_ 
auto get() -> decltype((a_)) 
{ 
    return a_; 
} 

ou si C++1y is available:

// 1. Return const reference to a_ 
auto& get() const 
{ 
    return a_; 
} 

// 2. Return non-const reference to a_ 
auto& get() 
{ 
    return a_; 
} 
+0

Ne devrait pas 'auto & get() const {return a_; } 'be' const auto & get() const {retourne a_; } 'si vous voulez renvoyer une référence const? La const a après le nom de la fonction signifie que vous pouvez appeler la fonction membre sur un objet constant auquel elle appartient. – SU3

+0

'auto &' peut déduire une référence au type const très bien. 'const auto &' dans ce cas ne serait pas plus correct, seulement plus explicite. – Casey

Questions connexes