2017-07-22 2 views
0

Tenir compte:C++ SFINAE pour choisir une surcharge entre le type de référence et l'argument converti en référence?

struct BigData {...}; 

// Let's get a BigData by reference, but use it as a value. 
// For example, we may want to make a copy of the object, but we'd 
// like to avoid the pass-by-value overhead at the call site. 
template <typename T, *some template magic?*> 
void processData(T& t) { 
    printf("Your BigData was converted to a reference argument.\n"); 
    ... 
} 

// Now, we want an overload that will know that there wasn't a 
// conversion to reference and will treat it like a reference. 
// Perhaps we are adding this BigData to a list of references. 
template <typename T, *some template magic?*> 
void processData(T& t) { 
    printf("You gave me a BigData reference.\n"); 
    ... 
} 

int main() { 
    BigData data; 
    BigData& ref = data; 

    processData(data); // "Your BigData was converted to a reference argument." 
    processData(ref); // "You gave me a BigData reference." 

    return 0; 
} 

En bref, mon objectif est d'avoir une distinction entre les surcharges qui, où la liaison d'une référence provenait - soit une valeur du type ou d'un type de référence (déjà). J'ai essayé d'utiliser std::enable_if et de la famille en combinaison avec des surcharges qui font et ne prennent pas de références à T, mais je ne peux pas trouver un moyen d'accomplir cela. Toute aide est grandement appréciée!

Répondre

3

Je pense que vous ne comprenez pas comment la liaison de référence fonctionne. Vous ne pouvez pas lier uniquement une référence à une autre référence, mais aussi une valeur qui est de type valeur (non référence qualifiée)

Donc, si vous voulez passer l'objet BigData par référence, il vous suffit de faire le

suivant
template <typename T> 
void processData(T& t) { 
    cout << "Your BigData was passed as a reference argument" << endl; 
    // ... 
} 

int main() { 
    BigData data; 
    BigData& ref = data; 

    processData(data); 
    processData(ref); 

    return 0; 
} 

Ici, les deux appels processData passeront l'objet BigData par référence (c.-à-d. Aucune copie pendant l'appel de fonction).

Vous n'avez pas besoin de traiter le cas où l'objet transmis à la fonction est une référence distincte du cas normal. std::enable_if n'est pas requis ici.

De plus, il n'y a aucun moyen de différencier les deux cas, soit en utilisant data ou ref comme arguments pour les fonctions car ils sont tous les deux lvalues. Vous devrez faire quelque chose comme ce qui suit, si vous voulez vérifier si le decltype de l'expression est une référence ou non

#include <iostream> 
#include <type_traits> 

using std::cout; 
using std::endl; 

template <typename T, std::enable_if_t<std::is_reference<T>::value>* = nullptr> 
void processData(std::add_lvalue_reference_t<T>) { 
    cout << "You gave me a reference argument." << endl; 
} 

template <typename T, std::enable_if_t<!std::is_reference<T>::value>* = nullptr> 
void processData(std::add_lvalue_reference_t<T>) { 
    cout << "Your argument was converted to a reference." << endl; 
} 

int main() { 
    auto integer_value = 1; 
    const auto& integer_ref = 2; 
    processData<decltype(integer_value)>(integer_value); 
    processData<decltype(integer_ref)>(integer_ref); 

    return 0; 
} 
+0

droit. Je comprends cela, mais mon objectif est d'avoir des surcharges qui distinguent d'où vient la liaison - soit une valeur du type ou un type (déjà) de référence. –

+0

@BrandonKammerdiener jeter un oeil à la réponse mise à jour – Curious

+0

Merci. C'est aussi loin que je l'ai eu, mais idéalement, je voudrais éviter de modifier l'appel. J'apprécie ton aide! –