2

私は何度も SFINAE をうまく使いました。クラスが関数を提供しているかどうかを検出することは問題ではありません。私の現在の問題は、彼の問題とは正反対のようです! 派生メソッドも検出する代わりに、クラスのメソッドのみを検出することをお勧めします。メソッドがテンプレートであることが関係しているようです。

クラス テンプレート メソッドを検出することは可能ですか? 害を及ぼさないタイプでテンプレートをインスタンス化しようとしましたが、うまくいきませんでした。

struct A { template<class T> void Func( T ) {}; };
struct B :A {};

template< class T >
struct CheckForFunc
{
    typedef char(&YesType)[1];
    typedef char(&NoType)[2];
    template< class U, void (U::*)( int ) > struct Sfinae;

    template< class T2 > static YesType Test( Sfinae<T2,&T2::Func>* );
    template< class T2 > static NoType  Test( ... );
    static const bool value = sizeof(Test<T>(0))==sizeof(YesType);
};

int main(int argc, char* argv[])
{
    // gives "1"
    std::cout << "Value A=" << CheckForFunc< A >::value << std::endl;
    // doesn't compile!
    std::cout << "Value B=" << CheckForFunc< B >::value << std::endl;
    return 0;
}

エラーメッセージ:

error: ‘&amp;A::Func’ is not a valid template argument for type ‘void (B::*)(int)’ because it is of type ‘void (A::*)(int)’

この SFINAE は、派生ではなく、テンプレート メソッドで非常にうまく機能することに注意してください。悪いのは、間違っていることを検出するだけでなく、コンパイルに失敗することです。

「サンプル」タイプ (ここでは int) を使用せずに SFINAE テストを作成する方法は?

編集: 申し訳ありませんが、C++03 のみです! そして、LLVMはそれで問題ありませんでした.VS2008でもありましたが、GCCとQNXではありませんでした(明日見なければならないバージョン)。

Edit2: Coliru を知らなかった! 非常にクールです、ここにエラーがあります!

4

4 に答える 4

2

私はこの修正を使用します:

Sfinae<T2, decltype(std::declval<T2>().Func(0))> 

つまり、式のを使用してクラス テンプレートobj.Func(0)に渡します。Sfinae

修正を加えた完全なコードは次のとおりです。

#include <iostream>
#include <utility>

struct A { template<class T> void Func( T ) {}; };

struct B : A {};

struct C {};

template< class T >
struct CheckForFunc
{
    typedef char(&YesType)[1];
    typedef char(&NoType)[2];
    template< class, class > struct Sfinae;

    template< class T2 > static YesType Test( Sfinae<T2, decltype(std::declval<T2>().Func(0))> * );
    template< class T2 > static NoType  Test( ... );
    static const bool value = sizeof(Test<T>(0))==sizeof(YesType);
};

int main(int argc, char* argv[])
{
    std::cout << "Value A=" << CheckForFunc< A >::value << std::endl;
    std::cout << "Value B=" << CheckForFunc< B >::value << std::endl;
    std::cout << "Value C=" << CheckForFunc< C >::value << std::endl;
    return 0;
}

出力:

Value A=1
Value B=1
Value C=0

Cこのデモにクラスを追加しました。

オンラインデモ。:-)

于 2013-08-06T17:06:49.823 に答える
1

C++20 に更新 (概念を使用) すると、このきちんとした constexpr ソリューションが得られます

#include <iostream>

struct A { template<class T> void Func( T ) {}; };
struct B : A {};
struct C {};

template <typename T>
concept CheckForFunc = requires(T t) { t.Func(T());  };

int main(int argc, char* argv[])
{
    if constexpr(CheckForFunc<A>)        std::cout << "Value A" << std::endl;
    if constexpr(CheckForFunc<B>)        std::cout << "Value B" << std::endl;
    if constexpr(CheckForFunc<C>)        std::cout << "Value C" << std::endl;
    return 0;
}

出力は次のようになります

Value A
Value B
于 2022-01-25T21:51:36.633 に答える
0

メンバー関数テンプレートに必要な正確なテンプレート パラメーターがわかっている場合は、次のように動作します (C++03 機能に置き換えることができるいくつかの C++11 機能を使用していることに注意してください)。

#include <iostream>
#include <type_traits>

struct A { template<class T> void Func( T ) {} };
struct B :A {};

template< class T >
struct CheckForFunc
{
    typedef char(&YesType)[1];
    typedef char(&NoType)[2];

    template< class T2 > static YesType Test(
        typename std::enable_if<
            std::is_same<void (T::*)(int), decltype(&T2::template Func<int>)>{},
            int
        >::type );
    template< class T2 > static NoType  Test( ... );
    static const bool value = sizeof(Test<T>(0))==sizeof(YesType);
};

int main(int argc, char* argv[])
{
    // gives "1"
    std::cout << "Value A=" << CheckForFunc< A >::value << std::endl;
    // doesn't compile!
    std::cout << "Value B=" << CheckForFunc< B >::value << std::endl;
    return 0;
}

出力:

値 A=1
値 B=0

于 2013-08-06T17:49:15.500 に答える