根据类型源自的类重写模板函数

时间:2019-05-10 17:46:49

标签: c++

这里首先是一个简单的示例,以更好地解释我的意思。

template <typename T>
class TemplateClass
{
public:
    void print();
};

template <>
void TemplateClass<int>::print()
{
    std::cout << "T is an int!" << std::endl;
}

template <>
void TemplateClass<float>::print()
{
    std::cout << "T is a float!" << std::endl;
}

int main()
{
    TemplateClass<int> i;
    i.print();

    TemplateClass<float> f;
    f.print();

    system("PAUSE");
}

在此,我根据T是int还是float来覆盖print()函数。

程序打印:

T is an int!
T is a float!
Press any key to continue . . .

我真正想要做的是基于派生自哪个类T的此类覆盖,可以从中派生T的类是其他模板类,因为它们使用了好奇的递归模板模式。

这是我尝试过的,我想不出其他任何方式

template <typename T>
class BaseOne {};

template <typename T>
class BaseTwo {};


struct DerivedOne : public BaseOne<DerivedOne>
{
    int i;
};

struct DerivedTwo : public BaseTwo<DerivedTwo>
{
    float x, y, z;
};

template <typename T>
class TemplateClass
{
public:
    void print();
};

template <typename U>
void TemplateClass<BaseOne<U>>::print()
{
    std::cout << "U is derived from BaseOne!" << std::endl;
}

template <typename U>
void TemplateClass<BaseTwo<U>>::print()
{
    std::cout << "U is derived from BaseTwo!" << std::endl;
}

int main()
{
    TemplateClass<DerivedOne> d1;
    d1.print();

    TemplateClass<DerivedTwo> d2;
    d2.print();

    system("PAUSE");
}

程序应打印:

U is derived from BaseOne!
U is derived from BaseTwo!
Press any key to continue . . .

但是我却得到了错误

// I believe this is the main error
Error (active)  E0498   template argument list must match the parameter list

// And these errors comes as a result of the error above
Error   C2039   'print': is not a member of 'TemplateClass<BaseOne/BaseTwo<T>>'
    // BaseOne/BaseTwo on respective lines in code
Error   C2447   '{': missing function header (old-style formal list?)

在线

void TemplateClass<BaseOne<U>>::print()
and
void TemplateClass<BaseTwo<U>>::print()

我有点迷路,不胜感激!

3 个答案:

答案 0 :(得分:4)

有一个for key, values in d.items():类型的特征。

is_base_of

此外,std::is_base_of_v<BaseOne<T>, T>将永远不会在static_assert(false)GCC上进行编译。使条件取决于类型参数将起作用。

Clang

顺便说一句,您真的需要static_assert(sizeof(T) < 0)吗?您可以在C ++ 17中使用if constexpr:

overriding/specialization

如果您确实需要覆盖/专业化,请使用template <typename T> void TemplateClass<T>::print() { if constexpr (std::is_convertible_v <TemplateClass<T>*, BaseOne*>) std::cout << "U is derived from BaseOne!" << std::endl } else if (std::is_convertible_v <TemplateClass<T>*, BaseTwo*>) { std::cout << "U is derived from BaseTwo!" << std::endl; } else { static_assert(false); // add error } } (SFINAE)

答案 1 :(得分:0)

您可以对课程进行部分专业化,但必须对整个课程进行部分专业化。您正在尝试仅对课程的 part 部分进行专业化。

像这样的事情会有效

template <typename T>
class TemplateClass<BaseOne<T>>
{
public:
    void print()
    {
        std::cout << "U is derived from BaseOne!" << std::endl;
    }
};

由于TemplateClass<DerivedOne>TemplateClass<BaseOne<DerivedOne>>不同,因此代码仍然无法正常工作。完全专业化和部分专业化匹配确切的类型,并且不考虑继承。

使用Ben所建议的类型特征。

答案 2 :(得分:0)

您不能部分专门化方法/功能。

您可以像int / float那样完全专精。

我建议标签分发,因为您可以轻松添加新的(模板化)重载:

template <typename> struct Tag {};

template <typename T>
class TemplateClass
{
public:
    auto print() -> decltype(helper_print(tag<T>{});) // SFINAE friendly
    // void print() // Simple, but SFINAE unfriendly
    { return helper_print(tag<T>{}); }
};

然后,您之前的代码将是:

void helper_print(Tag<int>)
{
    std::cout << "T is an int!" << std::endl;
}
void helper_print(Tag<float>)
{
    std::cout << "T is a float!" << std::endl;
}

您甚至可以添加模板化标签:

template <typename U>
void helper_print(Tag<std::vector<U>>)
{
    std::cout << "T is a std::vector!" << std::endl;
}

第二部分,因为您需要SFINAE和特征,所以比较棘手:

// Create traits
template <template <typename> class C, typename U>
std::true_type HasTemplateBaseImpl(C<U>*);

template <template <typename> class C>
std::false_type HasTemplateBaseImpl(...);

template <typename T, template <typename> class C>
using has_template_base = decltype(HasTemplateBaseImpl<C>(std::declval<T*>()));

然后

template <typename T,
          std::enable_if_t<has_template_base<T, BaseOne>::value, bool> = false>
void helper_print(Tag<T>)
{
    std::cout << "T is derived from BaseOne!" << std::endl;
}

template <typename T,
          std::enable_if_t<has_template_base<T, BaseTwo>::value, bool> = false>
void helper_print(Tag<T>)
{
    std::cout << "T is derived from BaseTwo!" << std::endl;
}

Demo