2016-09-27 4 views
1

この問題についての背景はありません。SFINAEのユーザー定義変換の場合

SFINAEを(直接または間接的にtype_traitsで)使用して、既存の関数、メンバー関数などをチェックする方法はたくさんあります。しかし:

最初の質問:クラスが特定のユーザー定義の変換演算子を実装しているかどうかを確認する方法はありますか?

私が何を意味するかを説明するために、このコードを検討してください。私は、任意のアサーション失敗することなく、このコードを実行したい:

#include <type_traits> 
#include <cassert> 

struct NotADouble { 
}; 
struct Double { 
    // explicit or not - you decide 
    explicit operator double() { 
     return 1.; 
    } 
}; 
// CORRECT THIS: ... 
template<typename T, 
    class = decltype(static_cast<double>(std::declval<T>()))> 
int f(T) { 
    return 1; 
} 
int f(...) { 
    return 2; 
} 
// ... UNTIL HERE 

int main() { 
    assert(f(NotADouble()) == 2); 
    assert(f(Double()) == 1); 
    assert(f(3.) == 2); 
    assert(f(3) == 2); 
    assert(f(3.f) == 2); 
} 

Tからdoubleの任意の標準的な変換シーケンスがあるかどうかfチェックの現在の実装で、Iは、これがこの場合にstd::is_convertibleと同じであると仮定する。

もう1つのアプローチは、最初の2つのテストを受け入れる次の実装です。

template<typename T> 
int f(T, double (T::*)() = nullptr) { 
    return 1; 
} 
int f(...) { 
    return 2; 
} 

質問2:NotADoubleは、任意の変換演算子を実装していませんが、このメンバ関数ポインタを許可しているようです。したがって、正確にはdouble (T::*)()とは何ですか、なぜそれはどのクラスにも存在しますか?

答えて

0

最初の質問:与えられた構造(C++ 14のコード)に変換演算子が定義されている場合は、チェックするためにヘルパー構造体を作成することができます。

#include <type_traits> 
#include <iostream> 

struct NotDouble { }; 
struct Double { 
    explicit operator double() { 
     return 1.0; 
    } 
}; 

template <class From, class To, class = void> 
struct HasConversionOperator: std::false_type { }; 

template <class From, class To> 
struct HasConversionOperator<From, To, decltype((&From::operator To), void())>: std::true_type { }; 

template <class From, class To, class = void> 
struct HasExplicitConversion: std::false_type {}; 

template <class From, class To> 
struct HasExplicitConversion<From, To, decltype(std::declval<To&>() = (To)std::declval<From&>(), void())>: std::true_type { }; 

template <class From, class To, class = void> 
struct HasImplicitConversion: std::false_type {}; 

template <class From, class To> 
struct HasImplicitConversion<From, To, decltype(std::declval<To&>() = std::declval<From&>(), void())>: std::true_type { }; 

template <class T> 
std::enable_if_t<HasConversionOperator<T, double>::value && HasExplicitConversion<T, double>::value && !HasImplicitConversion<T, double>::value> is_double(T d) { 
    std::cout << "has conversion to double" << std::endl; 
} 

template <class T> 
std::enable_if_t<!HasConversionOperator<T, double>::value || !HasExplicitConversion<T, double>::value || HasImplicitConversion<T, double>::value> is_double(T) { 
    std::cout << "don't have conversion to double" << std::endl; 
} 

int main() { 
    is_double(Double{}); 
    is_double(NotDouble{}); 
} 

出力:

has conversion to double 
don't have conversion to double 

第2質問:double (T::*)()はどのメンバーのタイプ所有者Tの関数ポインタで、パラメータを取らないdoubleを返します。変換演算子にはそのような署名があるだけでなく、さらに、クラスTにdoubleを返すメンバ関数がなくてパラメータを取らない場合でも、ポインタ型を作成することは完全に許可されていますが、ポインタ型の変数を任意の値で埋めることはできません。

+0

私が試したのと同様のテストがありましたが、参照がなく、明らかに十分ではありませんでした。 – overseas

+0

@ user3445587あなたは 'のアドレス演算子(&)を意味します。はい残念ながら、メンバ関数の参照を行う方法はありませんが、これは明らかに欠点ですが、直接的にはC++のメソッド呼び出しの構文によるものです。例えば。 'a.foo();' 'foo'をどのように解釈すべきでしょうか?スコープ内で使用可能な 'a'またはメンバ関数リファレンスのメンバ関数として...? –

関連する問題