2017-09-14 5 views
7

Recherche d'un alias make_shared sur un type de classe spécifique pour un constructeur spécifique de cette classe. Ma meilleure tentative:Alias ​​Constexpr de la fonction de modèle surchargé

class foo { public: foo(int x) : y(x) {} int y; }; 
constexpr auto newfoo = static_cast<std::shared_ptr<foo>(*)(int)>(std::make_shared<foo>); 

Rendement:

error: invalid static_cast from type ‘<unresolved overloaded function type>’ to type ‘std::shared_ptr<foo> (*)(int)’ 
constexpr auto newfoo = static_cast<std::shared_ptr<foo>(*)(int)>(std::make_shared<foo>); 

Qu'est-ce que je fais mal?

Répondre

4

std::make_shared est un modèle de fonction variadique. Vous spécifiez uniquement <foo> en tant que paramètre de modèle, mais vous aurez également besoin d'un int quelque part là-dedans. Quoi qu'il en soit, votre approche est vouée à l'échec car elle dépend de la façon dont les arguments de modèle de make_shared ont été présentés et parce qu'il est généralement difficile de travailler avec des jeux de surcharge en C++.

Ce que je suggère est de créer une fonction wrapper à la place:

constexpr auto newfoo(int x) 
{ 
    return std::make_shared<foo>(x); 
} 

À mon avis, il est plus facile d'écrire, lire et à comprendre. Si vous avez besoin vraiment SFINAE convivialité et noexcept, vous pouvez repeat the body three times:

constexpr auto newfoo(int x) 
    ->   decltype(std::make_shared<foo>(x)) 
     noexcept(noexcept(std::make_shared<foo>(x))) 
     {   return std::make_shared<foo>(x); } 

Une macro peut être utilisée pour rendre moins pénible la déclaration ci-dessus.


Si vous voulez vraiment un pointeur de fonction, cela semble fonctionner:

auto newfoo = 
    static_cast<std::shared_ptr<foo>(*)(const int&)>(
     &std::make_shared<foo, const int&>); 

Regardez la déclaration de make_shared:

template< class T, class... Args > 
shared_ptr<T> make_shared(Args&&... args); 

Vous devez fournir T=foo et quelque chose pour Args... . Étant donné que Args... est un paquet de référence de transfert, il en déduira toujours références de lvalue ou références rvalue. C'est pourquoi <foo, const int&> est un ensemble valide de paramètres de modèle et <foo, int> ne l'est pas.

Comme Zefick souligné dans les commentaires, tout cela peut être simplifié à:

constexpr auto newfoo = &std::make_shared<foo, const int&>; 

Le casting est pas vraiment nécessaire ici.

+1

+1, mais vous devriez probablement utiliser 'const int &' au lieu de 'int &&' dans votre exemple "si vous voulez vraiment". Tel quel, 'const int i = 42; auto f = newfoo (i); 'ne fonctionnera pas. –

+0

@MilesBudnek: bon point, a changé ma réponse –

+2

'constexpr auto newfoo = std :: make_shared ' fonctionne juste. Pourquoi avons-nous besoin de la distribution? – Zefick