2017-01-17 7 views
0

テンプレート化された関数で完全転送を使用してl値またはr値が保持されるようにしたいと考えていますが、同時に可能なパラメータタイプに一定の制限を課したいと思います。タイプ制限付きの完璧な転送

たとえば、Tを呼び出し可能オブジェクトに制限したいとします。 次のアプローチは、私

template<typename T> 
typename std::enable_if<std::is_callable<T>>::value>::type myFun(T&& val) 
{ 
    foo(std::forward<T>(val)); 
} 

に正しく見えるが、私はまだ、まだ様々なSFINAEのニュアンスと完全に快適ではないですので、私は誰か他の人の意見をいただければ幸いです。

これは正しいことと慣用方法ですか?

+0

'Allowed_Type'用のテンプレートを特化ない理由をと一般的なテンプレートを無効にしますか? – wally

+0

それはよりよい解決策でしょうか? –

+2

(ほぼ)特定のタイプを処理する場合は常にオーバーロードが優先されます。 – AndyG

答えて

3

std::is_callableは、ところでC++ 17の機能です。

あなたの関数myFunは何も返さないので、戻り値としてenable_ifを入れるのはちょっと変です。うん、テンプレートが選択されている場合には、voidになるでしょうが、それは、デフォルトのテンプレート引数としてそれを置くためにおそらくより読みやすいです:

template<typename T, std::enable_if_t<std::is_callable_v<T()>, int> = 0> 
void myFun(T&& val) 
{ 
    foo(std::forward<T>(val)); 
} 

Demo

それはあなたのenable_ifのために少し奇妙になりますが、真空中に存在する。少なくとも、私たちはstatic_assert経由で収まると良いコンパイラエラーをユーザに提供していないすべてのタイプキャッチする必要があります

template<typename T, std::enable_if_t<std::is_callable_v<T()>, int> =0> 
void myFun(T&& val) 
{ 
    foo(std::forward<T>(val)); 
} 

template<typename T, std::enable_if_t<!std::is_callable_v<T()>, int> =0> 
void myFun(T&& val) 
{ 
    static_assert(sizeof(T) == 0, "myFun is only callable with an argument that can be called as a function with no params"); 
} 

Demo2

+0

MSVCが壊れていて、それを理解できないという問題を除いて、 'std :: enable_if_t {}、 int> = 0'は 'typename = std :: enable_if_t {}>'よりも優れたオーバーロード解決プロパティを持っています。 – Yakk

+0

@ヤク:更新されました。ありがとうございます。 'std :: enable_if_t {}、int> = 0'と' template :: value、int> = 0>の間にプリファレンスがありますか? '前者には' bool 'への暗黙的な変換があり、 ':: value'をチェックする必要はないという事実以外にも? – AndyG

+0

':: value'は' {} 'よりも5文字多いです。代わりに、これはC++ 17の特性であるので、 'std :: is_callable_v 'と同じくらい短いです。 – Yakk

関連する問題