2010-12-09 42 views
2

Probablement une autre question stupide qui résulte de mon étude dans le mauvais livre C++ (j'ai l'intention de corriger cela).Erreur de type dans une fonction de modèle

Je joue avec sstream et essayé la fonction suivante:

template <class num> num fromString(const std::string& str) { 
    std::istringstream ss(str); 
    num temp; 
    ss >> temp; 
    return temp; 
} 

Quand je l'appeler comme:

int i = fromString<int>("123"); 

cela fonctionne bien. Mais si je l'appelle aime:

int i = fromString("123"); 

j'ai eu une erreur de compilation:

error: no matching function for call to ‘fromString(std::string&)’ 

Je pensais que le compilateur comprendrait que si j'assignant la valeur à un int alors je dois parler de fromString<int>, mais il semble que ce ne soit pas le cas.

Ai-je raté quelque chose? Dois-je toujours spécifier le type d'une fonction basée sur un modèle? Ou juste quand le type de modèle est le type de retour? Ou juste quand le type de modèle ne peut pas être déterminé par les types d'entrées?

Répondre

9

Non, le compilateur ne peut pas déduire les paramètres de modèle du type de retour seul. Vous devez être précis que vous étiez à l'origine:

int i = fromString<int>("123"); 

L'une des raisons pour lesquelles le compilateur ne peut pas déduire dans ce cas, car un certain nombre de types pourrait être convertible en int. Par exemple:

class Gizmo 
{ 
public: 
    operator int() const; 
}; 

Comment le compilateur sait pas à instancier fromString<Gizmo>() dans ce cas?

+0

humm ... Méchant! Je l'ai maintenant. Merci. Je suppose que je suis trop habitué à Haskell, qui est purement fonctionnel et donc ce genre de conversion automatique n'est pas possible. –

+0

Heh, gâté par C++. Je n'ai jamais entendu ça. :) –

1

En plus de ce que Jean dit au sujet de ce qui est ce qu'on appelle un « contexte non déduisent », vous pouvez parfois contourner des choses comme cela en fournissant un paramètre fictif du type de modèle:

#include <sstream> 
#include <string> 

template <typename T> 
T from_string(const std::string& s, const T& /*dummy*/) 
{ 
    std::stringstream ss; 
    ss << s; 
    T t; 
    ss >> t; 
    return t; 
} 

int main() 
{ 
    std::string s = "23"; 
    int i = from_string(s, i); 
    return 0; 
} 

Ce aide le compilateur à déduire le type et évite de devoir le spécifier explicitement. C'est particulièrement utile lorsque le nom de la variable est joli et court, comme dans l'exemple ci-dessus.

3

Vous pouvez obtenir cet effet avec une astuce simple.

#include <sstream> 
#include <string> 
using namespace std; 

struct from_string { 
    string str; 
    from_string(const string& s) : str(s) { } 
    template <typename T> 
    operator T() const { 
     T ret; 
     stringstream ss(str); 
     ss >> ret; 
     return ret; 
    } 
} 

int main() { 
    string s("1234"); 
    int a = from_string(s); 
    return 0; 
}