2017-10-11 6 views
0

J'ai une classe intitulée Eclipse avec un membre struct privé contenant ~ 30 champs de différents types de données.Méthode d'écriture avec le type de retour arrière à modifier en fonction de l'appel de la méthode?

J'ai une méthode qui retournera un champ de données de la structure, basé sur un nombre de champ passé en tant que paramètre. Voyant que la structure contient des données de différents types, j'ai choisi d'utiliser le mot-clé auto avec un type de retour arrière basé sur un paramètre basé sur un modèle. Mon en-tête de méthode est ci-dessous.

template<typename TheType> 
auto getColumnData(TheType toGet, int fieldNum) -> decltype(toGet) { 
    // switch statement to return fields based on fieldNum 
} 

Si je veux retourner une colonne qui est un int, j'appelle getColumnData(0, 1);. Le premier paramètre est uniquement utilisé pour déterminer le type de retour de la méthode et le deuxième paramètre détermine le numéro de champ à renvoyer à l'appelant de la méthode.

En théorie, le type de retour getColumnData() serait int et renvoyer la première colonne (correspondant au premier champ) de la structure. Mais je reçois cette erreur de compilation:

no viable conversion from returned value of type 'std::string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') to function return type 'decltype(toGet)' (aka 'int')`

Je comprends que si je devais appeler cette méthode avec un int comme premier paramètre, et un numéro de champ qui correspond à un champ de retour d'un std::string, il y aurait problèmes. Mais, basé sur des vérifications dans d'autres classes, ce cas ne se produirait jamais.

Est-il possible de forcer mon compilateur à accepter ce code, même si cela peut ne pas être correct dans certains cas?

Je sais que je pourrais juste surcharger la méthode, mais je préfère ne pas avoir plusieurs méthodes différentes pour essentiellement le même but si je peux comprendre comment accomplir la tâche dans un seul.

Aussi, si ma compréhension de l'une de ces informations semble incorrecte, s'il vous plaît faites le moi savoir. Je suis très nouveau en C++, donc je suis en train d'apprendre ces fonctionnalités au fur et à mesure.

+0

Ceci est complètement incorrect. Si le premier paramètre est un 'int', le' decltype' spécifie que la fonction renvoie un 'int', par définition. Arrêt complet. Fin de l'histoire. Tout ce que vous avez écrit à partir de là n'est pas pertinent. La fonction de modèle instancié doit renvoyer un 'int', no ifs, ands ou buts. –

Répondre

0

Vous ne pouvez pas modifier dynamiquement le type de retour d'une méthode au moment de l'exécution, comme vous le faites. Votre premier paramètre n'est pas un type de données connu lors de la compilation. C'est juste un entier qui est rempli au moment de l'exécution, donc vous ne pouvez pas du tout prendre de décisions à la compilation.

Une solution simple consisterait à utiliser std::variant (17 C++ ou ultérieur) ou boost::variant (11 C++ et versions ultérieures) comme le type de retour:

using FieldType = std:::variant<int, std::string>; 

FieldType getColumnData(int fieldNum) { 
    // switch statement to return fields based on fieldNum 
} 

int i = std::get<int>(getColumnData(1)); 
std::string s = std::get<std::string>(getColumnData(2)); 

Autrement , vous devez faire le type de retour être un paramètre de modèle, pas un paramètre de méthode:

template<typename TheType> 
TheType getColumnData(int fieldNum) { 
    // switch statement to return fields based on fieldNum 
} 

Mais alors vous rencontrez le problème que tous les champs ne seront pas convertibles en type de retour (ne peut pas retourner un champ std::string lorsqu'un est demandé, etc), donc vous ne pouvez pas simplement switch sur le fieldNum car ce n'est pas évalué à la compilation.

Vous pourriez être tenté de faire le numéro de champ soit un paramètre de modèle il est donc constant à la compilation, et ensuite se spécialiser sur elle:

template<const int FieldNum> 
auto getColumnData() { return 0; }; 

template<> int getColumnData<1>() { return private_struct.Field1; } 
template<> std::string getColumnData<2>() { return private_struct.Field2; } 
// etc... 

int i = getColumnData<1>(); 
std::string s = getColumnData<2>(); 

Mais je reçois des erreurs lorsque j'essaie de faire cela sur une méthode de classe basée sur un modèle ("spécialisation explicite dans une portée sans espace de noms").

Vous pourriez être tenté de le faire quelque chose comme, et nous espérons que le compilateur optimise loin les branches inutilisées:

template<const int FieldNum> 
auto getColumnData() { 
    if (FieldNum == 1) return private_struct.Field1; 
    if (FieldNum == 2) return private_struct.Field2; 
    //etc... 
    return 0; 
} 

ou

template<const int FieldNum> 
auto getColumnData() 
{ 
    switch (FieldNum) { 
     case 1: return private_struct.Field1; 
     case 2: return private_struct.Field2; 
     // etc... 
    } 
    return 0; 
}; 

int i = getColumnData<1>(); 
std::string s = getColumnData<2>(); 

Mais ce n » t travail, soit (erreurs "déduction incohérente pour le type de retour automatique").