2014-09-17 4 views
10

J'ai le problème suivant que je ne vois juste pas une bonne solution à (et peut-être il n'y en a pas): J'ai une méthode sur modèle où le type de retour dépend de l'entrée tapez, et grâce à C++ 11 decltype le type de retour peut être dériver facilement, mais Je voudrais également permettre à l'utilisateur de définir le type de retour explicitement si désiré.Modèle de fonction C++: Type de retour dérivé et explicite

Plus formellement j'ai une fonction de modèle f, que je voudrais être appelable comme f(x), avec ni l'entrée ni le type de retour explicitement défini. Et je voudrais aussi pouvoir l'appeler f<ret_t>x() avec le type de retour explicitement défini, mais le type d'entrée est toujours dérivé automatiquement.

Maintenant, satisfaisant la première contrainte avec C++ 11 est facile (supposons qu'il ya une autre méthode basé sur un modèle:

template<typename InT> 
auto f(const InT& in) -> decltype(/* code deriving the return type using in */); 

Mais cela ne permettra pas primordial du type de retour, pour que je dois ajouter comme un second paramètre de modèle et déplacer la dérivation decltype dans la définition du modèle et probablement besoin d'utiliser std::declval<InT> ou std::result_of:

template< 
    typename InT, 
    typename RetT = /* code deriving return type using InT and declval/result_of */> 
RetT f(const InT& in); 

Cependant, cette façon je toujours aussi explicitement d efine InT lors de l'appel f. Ainsi, la déclaration de f afin de pouvoir laisser InT ouvert, mais préciser RetT devrait être:

template< 
    typename RetT = /* code deriving return type using InT and declval/result_of */, 
    typename InT> 
RetT f(const InT& in); 

Mais depuis au point où je dois spécifier une valeur par défaut pour RetT, InT est pas encore disponible et donc Ne peut pas être utilisé. La meilleure solution de contournement que je puisse trouver jusqu'ici, ce qui n'est pas très satisfaisant et ne semble pas fonctionner car la déduction de RetT échoue (apparemment parce que vous ne pouvez pas déduire les types des arguments par défaut), est:

template<typename RetT, typename InT> 
RetT f(
    const InT& in, 
    const RetT& = std::declval</* code deriving return type using InT or in and declval/result_of */>()); 

y at-il de meilleures façons d'avoir une valeur par défaut pour RetT qui dépend InT tout en étant en mesure de préciser explicitement RetT si on le souhaite? Il est important de noter que le type de retour doit être disponible dans l'implémentation de la fonction pour que l'objet de RetT soit affecté directement et seulement une fois dans le corps de la méthode.

+0

La dernière ligne est brisée de deux façons: vous ne pouvez pas utiliser ODR 'declval' et vous ne pouvez pas déduire un argument par défaut. –

+0

@Niall: Oui, 'result_of' fonctionnerait probablement. Mais la question concerne l'ordre des arguments dans ce cas. –

+0

@ T.C.: Maintenant que vous le mentionnez, oui vous ne pouvez pas déduire d'un argument par défaut. Je vais mentionner ceci. –

Répondre

10

Vous pouvez utiliser std::conditional et un type dummy pour vérifier si la fonction a un type déduit automatique ou un type sélectionné par l'utilisateur.

Si l'utilisateur sélectionne explicitement un type de retour, le type de retour sera quelque chose de différent du type dummy et ce sera le type de retour de la fonction. Sinon, utilisez simplement le type déduit comme avant.

Après un exemple d'utilisation:

#include <typeindex> 
#include <type_traits> 
#include <iostream> 

struct dummy 
{ 
}; 

template<typename RetType = dummy, typename T> 
auto f(const T& in) 
-> typename std::conditional<std::is_same<RetType, dummy>::value, T, RetType>::type 
{ 
    std::cout<<typeid(RetType).name()<<" "<<typeid(T).name()<<std::endl; 
    return in; 
} 

int main() 
{ 
    f(1); 
    f<float>(1); 
} 
+0

Probablement même pas besoin d'utiliser 'dummy' -' void' est probablement suffisant. –

+0

@ T.C. Si les utilisateurs sélectionnent void comme type de retour, le type déduit automatique sera utilisé. Je ne pense pas que cela soit souhaité – Felics

+0

Un argument de modèle par défaut avant ceux qui ne sont pas par défaut ... Je ne le savais pas. C'est cool. – Niall

Questions connexes