派生类模板中的条件覆盖

Car*_*ton 9 c++ inheritance templates sfinae c++11

我有一个Container保存的对象,其类型可以从一些基类的任何组合衍生的(类TypeA,TypeB等).基类Container具有返回指向包含对象的指针的虚方法; nullptr如果包含的对象不是从期望的类派生的,那么它们应该返回.我想根据Container模板参数有选择地覆盖base的方法.我尝试使用SFINAE如下,但它不编译.我想避免专注Container于所有可能的组合,因为可能有很多.

#include <type_traits>
#include <iostream>

using namespace std;

class TypeA {};
class TypeB {};
class TypeAB: public TypeA, public TypeB {};

struct Container_base {
    virtual TypeA* get_TypeA() {return nullptr;}
    virtual TypeB* get_TypeB() {return nullptr;}
};

template <typename T>
struct Container: public Container_base
{
    Container(): ptr(new T()) {}

    //Override only if T is derived from TypeA
    auto get_TypeA() -> enable_if<is_base_of<TypeA, T>::value, TypeA*>::type
    {return ptr;}

    //Override only if T is dervied from TypeB
    auto get_TypeB() -> enable_if<is_base_of<TypeB, T>::value, TypeB*>::type
    {return ptr;}

private:
    T* ptr;
};

int main(int argc, char *argv[])
{
    Container<TypeA> typea;
    Container<TypeB> typeb;
    Container<TypeAB> typeab;

    cout << typea.get_TypeA() << endl; //valid pointer
    cout << typea.get_TypeB() << endl; //nullptr

    cout << typeb.get_TypeA() << endl; //nullptr
    cout << typeb.get_TypeB() << endl; //valid pointer

    cout << typeab.get_TypeA() << endl; //valid pointer
    cout << typeab.get_TypeB() << endl; //valid pointer

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

C.M*_*.M. 4

...或者您可以将方法更改为更简单的方法:

template <typename T>
struct Container: public Container_base
{
    TypeA* get_TypeA() override
    {
        if constexpr(is_base_of_v<TypeA, T>)
            return ptr;
        else
            return nullptr;
    }

    ...
};
Run Code Online (Sandbox Code Playgroud)

并依靠优化器来抚平任何皱纹。就像用一个函数替换多个return nullptr函数一样(在最终的二进制文件中)。或者,如果您的编译器不支持if constexpr.

编辑:

...或者(如果您坚持使用 SFINAE)以下内容:

template<class B, class T, enable_if_t< is_base_of_v<B, T>>...> B* cast_impl(T* p) { return p; }
template<class B, class T, enable_if_t<!is_base_of_v<B, T>>...> B* cast_impl(T* p) { return nullptr; }

template <typename T>
struct Container: public Container_base
{
    ...

    TypeA* get_TypeA() override { return cast_impl<TypeA>(ptr); }
    TypeB* get_TypeB() override { return cast_impl<TypeB>(ptr); }

private:
    T* ptr;
};
Run Code Online (Sandbox Code Playgroud)