2016-05-24 4 views
2

多項式のテンプレートベースのクラスを作成しています。 (評価、多項式の間にいくつかの操作、分化、...)このように、: to_string機能(およびstd::ostream -leftシフト・オーバーライド)の場合template <typename _ty> class Polynomial{...C++ SFINAE演算子/関数の結果型チェック

、私は_ty<をサポートしている場合、チェックしなければなりませんでした-operator(つまり、実数はyes、複素数はno)、文字列をうまくフォーマットすることができます。このために私はこのコードを使用します要するに

#include <type_traits> 

template <class _op, class... _ty, typename = decltype(std::declval<_op>()(std::declval<_ty>()...))> 
std::true_type impl_test(const _op&, const _ty&...) { return std::true_type(); } 
std::false_type impl_test(...) { return std::false_type(); } 
template <class> struct supports; 
template <class _op, class... _ty> struct supports<_op(_ty...)> : decltype(impl_test(std::declval<_op>(), std::declval<_ty>()...)){}; 

#define is_ineq_supported(type) supports<std::less<>(type, type)>() 

をされていない場合、is_ineq_supported(type)<演算子はのための有効な過負荷がある場合std::true_typeを返し、false_type

template <typename _ty> void do_stuff(_ty arg, const std::true_type&) { 
    // do stuff with the '<'-operator 
} 

template <typename _ty> void do_stuff(_ty arg, const std::false_type&) { 
    // do stuff without the '<'-operator 
} 

template <typename _ty> void do_stuff(_ty arg) { 
    do_stuff(arg, is_ineq_supported(_ty)); 
} 

は、私はまた、内積とバイナリ*演算子はオーバーロードをVectorクラスを、持っているので、それが返されます:対応する機能は、このように、特徴的な引数としてtrue_typeまたはfalse_typeで呼び出すことができますdouble。しかし、多項式の場合、互いに乗算されたときに同じ型を返す係数と引数を持つことは意味があります。

私の問題は次のとおりです。指定された操作が指定された型を返すかどうかを調べる方法があります。 (多分似たようなマクロですか?)私が思うに、最も単純なのは、結果の型が引数型と一致する場合はtrue_typeを返し、それ以外の場合はfalse_typeを返します。もちろん、より一般的な解決法はさらに優れています。

IDEとコンパイラの問題点:私はデフォルト設定でVisual Studio 2015を使用しています。

+0

「*(... )指定された操作が指定された型を返すかどうか* "、返された型が何かに暗黙的に変換可能であるかどうかチェックするほうが良いでしょうか? –

+4

'std :: is_same'(または' std :: is_convertible')? – Jarod42

答えて

0

最終的にBoostに追加される、fit::is_callableを使用する一般的なクロスプラットフォームソリューションです。また、C++でstd::is_callableの目を離さないようにしてください。

必要はありませんマクロ:

#include <type_traits> 
#include <iostream> 
#include <fit/is_callable.hpp> 

// std::less doesn't SFINAE, so we make our own test 
struct less_test { 
    template<typename L, typename R> 
    auto operator()(L l, R r) -> decltype(l < r); 
}; 

template<typename T> 
using is_less_than_comparable = fit::is_callable<less_test, T, T>; 

// operator< version (replace with your implementation) 
template <typename T> constexpr auto 
do_stuff(T arg, const std::true_type&) { 
    return std::integral_constant<int, 0>{}; 
} 

// other version (replace with your implementation) 
template <typename T> constexpr auto 
do_stuff(T arg, const std::false_type&) { 
    return std::integral_constant<int, 1>{}; 
} 

template <typename T> constexpr auto 
do_stuff(T arg) { 
    return do_stuff(arg, is_less_than_comparable<T>{}); 
} 

struct foo {}; 

int main() { 

    //is not less-than comparable 
    static_assert(do_stuff(foo{}) == 1, ""); 

    //is less-than comparable 
    static_assert(do_stuff(0) == 0, ""); 
} 
0

あなたはおそらく、あなたのメンバーのメソッド検出器を再考し、最もC++ 11-っぽいvoid_tベースのソリューションを使用する必要があります。

template <class _op, class _ret, class... _ty> 
typename std::enable_if<std::is_same<decltype(std::declval<_op>()(std::declval<_ty>()...)), _ret>::value, std::true_type>::type 
impl_test(const _op&, const _ty&...) { 
    return std::true_type(); 
} 

それは次のようにこれは動作します:私はあなたのソリューションを更新しなければならなかった場合は、おそらく次のコードが実行可能なアプローチである、と述べた

struct S { int operator()() { return 42; } }; 

int main() { 
    assert((impl_test<S, int>(S{}))); 
    // this will give you an error at compile time 
    // assert((impl_test<S, double>(S{}))); 
} 
関連する問題