2016-11-29 11 views
2

一般的なケースでTを受け入れることができるように関数をテンプレート化する方法はありませんか、テンプレート引数が呼び出し可能なものに解決された場合は、ファンクタ、ファンクションポインタまたはstd::function?あなたが部分的に関数テンプレートを特化することはできませんので、あなたは、あなたの質問に示す構文を取得することはできませんTとTを返す関数オブジェクトの特殊化T

template<typename T> 
void use_this(T obj) { 
    obj->do_stuff(); 
} 

template<> 
void use_this<???>(??? func) { 
    use_this(func()); 
} 

use_this(MyObj); // should call first one 
use_this([MyObj](){ return MyObj; }); // should call the second one 

答えて

1

:たとえば
は、私はこのような何かをしたいと思います。

Tが引数なしで呼び出し可能な場合とそうでない場合の2つの関数テンプレートを記述できます。あなたは、それが利用可能なときオーバーロードの解決は、そのバージョンを好む作るためにexpression SFINAEを使用して機能バージョンを無効にして、余分な機能パラメータを追加することができます。

template<typename T> 
void use_this(T obj, float) { 
    obj->do_stuff(); 
} 

template<typename Func> 
auto use_this (Func func, int) -> decltype(func(), void()) { 
    use_this(func()); 
} 

次にあなたが曖昧引数そのものを提供するラッパーを追加することができます。

template <typename T> 
void use_this(T&& t) { 
    use_this(std::forward<T>(t), 0); 
} 

Live demo

0
namespace details { 
    template<template<class...>class Z, class, class...Ts> 
    struct can_apply : std::false_type{}; 
    template<template<class...>class Z, class...Ts> 
    struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...> : std::true_type{}; 
} 
template<template<class...>class Z, class...Ts> 
using can_apply = details::can_apply<Z,void, Ts...> 

template<class Sig> 
using can_invoke = can_apply< std::result_of_t, Sig >; 

現在特性クラスcan_invokeを持っています。

あなたは署名を渡します。署名が有効な呼び出しであれば真実で、そうでなければ偽ります。私はこのようなenable_if_tvoid_tresult_of_tのようないくつかのC++ 11を使用

template<class T> 
std::enable_if_t< !can_invoke<T()> > 
use_this(T obj) { 
    obj->do_stuff(); 
} 
template<class T> 
std::enable_if_t< can_invoke<T()> > 
use_this(T func) { 
    use_this(func()); 
} 

。すべてはC++ 11で簡単に記述でき、簡単に検索できます。

無効な署名が渡されたときのresult_ofの動作がC++ 14で変更されました。 C++ 11では、SFINAEに対応する必要はありません。次のように我々はC++ 11にinvoke_result_rstd::result_of_tを置き換えることができます。

template<class Sig, class=void> 
struct invoke_result {}; 
template<class Sig> 
using invoke_result = typename invoke_result<Sig>::type; 

template<class F, class...Args> 
struct invoke_result<F(Args...), 
    decltype(void(std::declval<F>()(std::declval<Args>()...))) 
> { 
    using type = decltype(std::declval<F>()(std::declval<Args>()...)); 
}; 

これは今SFINAEフレンドリーです。

can_applyは、C++ 20のis_detectedに似ていますが、短くポイントまでです。

MSVCのような非C++ 11コンパイラでこれを実行することは実用的ではないことに注意してください。しかし、タグのディスパッチと同様のことができます。

関連する問題