2017-10-05 1 views
3

J'ai besoin de convertir une chaîne qui représente un vecteur de T s dans le vecteur correspondant.Passer la fonction avec les valeurs par défaut comme argument les ignorer

Mon problème est que je voudrais passer un argument simple: la fonction de convertisseur. Voici le split:

template <class T> 
auto split(const std::string &s, const std::function<T(const std::string&)> &convert, char sep = ',') -> std::vector<T> 
{ 
    std::stringstream ss(s); 
    std::vector<T> result; 

    while (ss.good()) 
    { 
     std::string substr; 
     std::getline(ss, substr, sep); 
     if (!substr.empty()) 
      result.push_back(convert(substr)); 
    } 
    return result; 
}; 

Il ne peut pas compiler lors du passage des fonctions standard telles que std::stoi en raison des paramètres par défaut de std::stoi que sa signature est int stoi(const string& __str, size_t* __idx = 0, int __base = 10);:

auto q = split<int>(subs, std::stoi); 

error: no matching function for call to 'split' 
      auto q = split<int>(subs, std::stoi); 
        ^~~~~~~~~~ 

Et je ne peux évidemment tromper le compilateur par en utilisant une fonction lambda:

auto q = split<std::size_t>(subs, [](const std::string &s){ return std::stoul(s); }); 

Y at-il un truc de métaprogrammation qui me permet de som ehow ignorer les paramètres par défaut?

+0

Vous avez explicitement spécifié que vous voulez 'split '. – nwp

+0

Je veux dire que 'std :: stoi', en fait, a des paramètres par défaut: la signature est' int stoi (chaîne const & __str, taille_t * __idx = 0, int __base = 10); '. J'espère ignorer cette signature par défaut. – senseiwa

+0

Si vous ne pouvez pas utiliser std :: function, cela vous facilitera la vie. (Un paramètre de fonction basé sur un modèle serait préférable.) – alfC

Répondre

4
#define RETURNS(...) \ 
    noexcept(noexcept(__VA_ARGS__)) \ 
    -> decltype(__VA_ARGS__) \ 
    { return __VA_ARGS__; } 

#define OVERLOADS_OF(...) \ 
    [](auto&&...args) \ 
    RETURNS(__VA_ARGS__(decltype(args)(args)...) 

Cette macro vous permet de prendre le nom d'une fonction et de générer un lambda qui contient les surcharges de celui-ci.

auto q = split<std::size_t>(subs, OVERLOADS_OF(std::stroul)); 

qui est agréable et concis. Les arguments par défaut ne sont accessibles qu'en appelant () sur le nom réel de la fonction, et le seul moyen de "déplacer le nom" dans un contexte différent est de le placer dans un lambda sous forme de texte. En outre, il existe une proposition par @barry pour remplacer RETURNS(X) ci-dessus par => X pour lambdas. Je ne suis pas au courant d'une proposition actuellement maintenue pour remplacer la macro OVERLOADS_OF (il y en avait une il y a un moment).

Il est possible que la proposition de réflexion vous permette d'accéder aux arguments par défaut et à l'ensemble de surcharge d'un nom de fonction, et que la métaprogrammation fantaisie vous permette de générer OVERLOADS_OF sans macro. Que voulez-vous dire par paramètres par défaut?

5

EDIT: Cela n'aide pas vraiment dans ce cas. Je le quitte parce que c'est utile dans d'autres cas, comme si vous aviez une fonction qui retournait quelque chose de convertible à T, mais cela ne résout aucun des problèmes avec stoi.


Ne spécifiez pas explicitement le type de la fonction. Soit convert être n'importe quel type; vous obtiendrez une erreur si vous essayez de passer quelque chose qui ne peut pas être appelé sur un std::string ou qui ne retourne pas quelque chose convertible en T. Il n'y a aucune raison de restreindre le type au-delà de cela, sauf si vous avez spécifiquement une raison pour laquelle il doit s'agir de ce type spécifique, et dans ce cas vous ne le faites pas.

Ainsi, vous pouvez déclarer votre fonction

template <class T, class F> 
auto split(const std::string &s, const F&& convert, char sep = ',') -> std::vector<T> 
+0

Cela ne fonctionnera pas si on passe 'strtoi' au point d'appel. – Yakk

+0

@Yakk Ugh, oui, les surcharges. Je ne pense pas que SFINAE puisse vraiment gérer cela, donc je ne sais pas s'il est possible de le faire fonctionner de manière transparente sur le site d'appel sans macros, mais je peux me tromper. –

+0

Pas même les surcharges. Avec des surcharges nulles, le pointeur ou la référence de la fonction passée (et qui doit être résolu en un objet à transmettre) ne comportera pas les arguments par défaut. Donc, au point d'appel, cela ne fonctionnera pas. – Yakk