0

関数テンプレートを作成しようとしています。一方のバージョンは、他方のバージョンの基準を満たさないすべてのタイプに使用する必要があります。引数が特定のクラスの基本クラス、またはそのクラス自体である場合は、他のバージョンを使用する必要があります。

のオーバーロードを試みましBase&たが、クラスが から派生した場合Base、特定のものではなく一般的なものを使用します。

私もこのSFINAEアプローチを試しました:

struct Base { };

struct Derived : public Base { };

struct Unrelated { };

template<typename T>
void f(const T& a, bool b = true) {
    cout << "not special" << endl;
}

template<typename T>
void f(const Base& t, bool b = is_base_of<Base, T>::value) {
    cout << "special" << endl;
}

Base b;
Derived d;
Unrelated u;

f(b); f(d); f(u);

しかし、それらはすべて「特別ではない」と出力されます。私は SFINAE が苦手で、おそらくやり方が間違っているだけです。このような関数をどのように書くことができますか?

4

3 に答える 3

3

まず、関数の引数から推測できないため、これらのいずれも「特別な」fオーバーロードを呼び出すことはありません。Tその最初のパラメーターは、次のタイプである必要がありますT

void f(const T& t, bool b = is_base_of<Base, T>::value)

それが完了したら、「特別な」オーバーロードは SFINAE を実際に使用してオーバーロードの解決に影響を与えないことに注意してください。 is_base_of<T, U>::value常に値がありtrueますfalseenable_ifオーバーロードの解決に影響を与えるには、ブール値に基づいて条件付きで型を定義するを使用する必要があります。

また、両方のオーバーロードで SFINAE を使用する必要があります。Tベースから派生した (またはベース型である) 場合は「特別な」オーバーロードを有効にする必要がありT、ベースから派生していない場合にのみ「特別ではない」オーバーロードを有効にする必要があります。そうしないと、オーバーロードの解決があいまいになります。

2 つのオーバーロードは、次のように宣言および定義する必要があります。

template<typename T>
void f(T const& a, typename enable_if<!is_base_of<Base, T>::value>::type* = 0)
{
    cout << "not special" << endl;
}

template<typename T>
void f(T const& t, typename enable_if<is_base_of<Base, T>::value>::type* = 0)
{
    cout << "special" << endl;
}

最後に、ここには特殊化がないことに注意してください。名前が付けられたこれら 2 つの関数fオーバーロードです。

于 2012-05-01T17:40:39.420 に答える
2

簡単な C++03 のアプローチを次に示します。

namespace detail // implementation details, users never invoke these directly
{
    template<bool B>
    struct f_impl
    {
        template<typename T>
        static void f(T const& t) { std::cout << "not special\n"; }
    };

    template<>
    struct f_impl<true>
    {
        static void f(Base const& t) { std::cout << "special\n"; }
    };
}

template<typename T>
void f(T const& t)
{
    detail::f_impl<is_base_of<Base, T>::value>::f(t);
}

ライブデモ

于 2012-05-01T17:37:37.987 に答える
0

オーバーロードでそれを行う 1 つの方法は次のようになります。

#include <iostream>

using namespace std;

struct Base { };

struct Derived : public Base { };

struct Unrelated { };

void f(...) {
    cout << "not special" << endl;
}

void f(const Base& t) {
    cout << "special" << endl;
}

int main(){ 
    Base b;
    Derived d;
    Unrelated u;

    f(b); 
    f(d);
    f(u);

    return 0;
}

結果:

special
special
not special

可変引数リストを取るオーバーロードは、任意の型の引数を取りますが、まったく機能する他のオーバーロードよりも常に適していないと見なされます。

于 2012-05-01T17:48:22.617 に答える