1

T が特定のタイプではない場合、テンプレートの特殊化を記述することなくFoo()、派生クラスでオーバーライドを無効にすることは可能でしょうか(または何らかのブースト マジックを使用) 。std::enable_ifclass Derived

ボーナス ポイント: T が特定のメソッドを定義していない場合、オーバーライドを無効にできますか?

これが私のSSCCEです:

#include <iostream>
#include <string>

class Base
{
public:
    virtual std::string Foo()
    {
        return "Base";
    }
};

template <typename T>
class Derived : public Base
{
public:
    virtual std::string Foo() override
    {
        return "Derived";
    }
};

int main()
{
    Derived<int> testInt;
    std::cout << testInt.Foo() << std::endl;

    Derived<float> testFloat;
    std::cout << testFloat.Foo() << std::endl;//I would like this to print 'Base'
}

アップデート:

素晴らしい解決策をありがとう、しかし私はそれらを私の実際のコードに適応させることができませんでした. 次の例は、私が達成しようとしていることのより良いアイデアを提供するはずです:

#include <iostream>
#include <string>

class Object
{
public:
    void Test()
    {
        std::cout << "Test" << std::endl;
    }
};

class EmptyObject
{
};

class Base
{
public:
    virtual std::string Foo()
    {
        return "Base";
    }
};

template <typename T>
class Derived : public Base
{
public:
    virtual std::string Foo() override
    {
        m_object.Test();
        return "Derived";
    }

private:
    T m_object;
};

int main()
{
    Derived<Object> testObject;
    std::cout << testObject.Foo() << std::endl;

    Derived<EmptyObject> testEmpty;
    std::cout << testEmpty.Foo() << std::endl;
}
4

4 に答える 4

1

クラスをテンプレートで特化する代わりに、メソッドを直接テンプレートで特化することができます: ( https://ideone.com/gYwt5r )

template<> std::string Derived<float>::Foo() { return Base::Foo(); }

そして、仮想メソッドにT追加することによって、将来のオーバーライドを無効にするクラスのテンプレートの特殊化のみが表示されます。final

于 2014-06-16T17:23:23.010 に答える
1

コンパイル時に特定の型を制限する必要がある場合は、次のものstd::enable_ifと一緒に使用できますstd::is_same

typename std::enable_if<std::is_same<T, float>::value, std::string>::type 
virtual Foo() override
{
    return "Derived";
}

Baseまたは、テンプレートの型が探している型ではない場合でも、メソッドへの呼び出しを簡単にリダイレクトできますstd::is_same

virtual std::string Foo() override
{
    return std::is_same<T, float>::value ? Base::Foo() : "Derived";
}

ボーナスに関しては、このSO answerからトレイトdecltypeを取得できますbar()

template <typename T>
class has_bar
{
    typedef char one;
    typedef long two;

    template <typename C> static one test(decltype(&C::bar) ) ;
    template <typename C> static two test(...);

public:
    enum { value = sizeof(test<T>(0)) == sizeof(char) };
};

制限は、引数または戻り値の型に制約を設定できないことです。

virtual std::string Foo() override
{
    return has_bar<T>::value ? "Derived" : Base::Foo() ;
}

ノート:

has_bar最初の例のようにと一緒にenable_if使用して、コンパイル時に無効にすることもできます。

于 2014-06-16T17:57:55.080 に答える
1

Derived::Fooこれを行うには、 if に基づいて条件付きで委任できる2 つの関数を作成しT = floatます。1 つは実際のDerived::Foo実装を含み、もう 1 つは を呼び出しますBase::Foo

template <typename T>
class Derived : public Base
{
public:
    virtual std::string Foo() override
    {
        return do_Foo(std::is_same<T, float>{});
    }

private:
    std::string do_Foo(std::false_type)
    {
        return "Derived";
    }
    std::string do_Foo(std::true_type)
    {
        return Base::Foo();
    }
};

ライブデモ


実際にやりたいことは、特定のメンバー関数を定義するDerived<T>::Foo()場合にのみ実装を呼び出すことであり、そうでない場合は呼び出す必要があります。これは、式 SFINAE を使用して行うことができます。TBase::Foo()

template <typename T>
class Derived : public Base
{
public:
    std::string Foo() override
    {
        return do_Foo(true);
    }
private:
    template<typename U = T>
    auto do_Foo(bool)
        -> decltype(std::declval<U>().test(), void(), std::string())
    {
        return "Derived";
    }
    std::string do_Foo(int)
    {
        return Base::Foo();
    }
};

ライブデモ

上記のコードでは、型Tが という名前のメンバー関数を定義していない場合test()do_Foo(bool)メンバー関数テンプレートは実行できません。一方、T::test()が存在する場合は、do_Foo(bool)に渡されるブール値が に比べて一致するため、 が選択さdo_Fooれます。Foodo_Foo(int)

decltype末尾の戻り値の型で式内で何が起こっているかについての詳細な説明は、ここにあります。

于 2014-06-16T17:28:15.153 に答える
1

階層に中間クラスを追加できます。

class Base
{
public:
    virtual std::string Foo()
    {
        return "Base";
    }
};

template <typename T>
class Intermediate : public Base
{
    // common operations with m_object

protected: // not private!
    T m_object;
};

template <typename T, typename = bool>
class Derived : public Intermediate<T> {};

template <typename T>
class Derived<T, decltype(std::declval<T>().Test(), void(), true)>
    : public Intermediate<T>
{
public:
    virtual std::string Foo() override
    {
        this->m_object.Test(); // this-> is necessary here!
        return "Derived";
    }
};

完全な例は、 clang 3.4g++ 4.8.2の両方で正常にコンパイルされます。

于 2014-06-16T19:59:44.243 に答える