阻止所有模板化派生类型的通用模板函数

时间:2012-12-16 13:53:58

标签: c++ templates c++11 metaprogramming overloading

这个问题遵循以下问题:Function overloading and template deduction priority

考虑以下课程:

template<typename T1, typename T2> 
class Base {};

class Derived0 : public Base<double, double> {};

template<typename T1, typename T2, typename T3> 
class Derived1 : public Base<T1, T2> {};

template<typename T1, typename T2, typename T3, typename T4> 
class Derived2 : public Base<T3, T4> {};

以下功能:

template<typename T> f(const T& x); // version A
template<typename T1, typename T2> f(const Base<T1, T2>& x); // version B

我的问题是,f(double)会调用version A(确定),f(Base<double, double>)会调用version B(确定),但f(Derived1<double, double, double>)会调用version A (请参阅开头的其他问题的链接)。

使用C ++ 11,无论version Aversion B是什么,如何阻止Base<T1, T2>并强制T1 T2的所有派生成员?

注意:如果可能的话,我想避免添加帮助程序类,而是希望在提供的类中添加成员。

2 个答案:

答案 0 :(得分:3)

这是一个可能适合你的特质。

特质类:

#include <type_traits>

template <typename, typename> struct Base { };

template <typename T> struct isbase
{
    typedef char yes;
    typedef yes no[2];

    template <typename U, typename V> static yes & test(Base<U, V> const &);
    static no & test(...);

    static bool const value = sizeof(test(std::declval<T>())) == sizeof(yes);
};

<强>应用

#include <iostream>

template <typename T>
typename std::enable_if<!isbase<T>::value>::type f(T const &)
{
    std::cout << "f(T const &)\n";
}

template <typename T1, typename T2>
void f(Base<T1, T2> const &)
{
    std::cout << "f(Base<T1, T2> const &)\n";
}

示例:

template<typename T1, typename T2, typename T3>
struct Derived1 : public Base<T1, T2> {};

int main()
{
    std::cout << isbase<double>::value << std::endl;
    std::cout << isbase<Base<int, char>>::value << std::endl;
    std::cout << isbase<Derived1<bool, bool, bool>>::value << std::endl;

    f(double{});
    f(Base<int, char>{});
    f(Derived1<bool, float, long>{});
}

泛化:我们可以制定更一般的特征来检查类型是否来自模板实例:

template <typename T, template <typename...> class Tmpl>
struct derives_from_template
{
    typedef char yes;
    typedef yes no[2];

    template <typename ...Args> static yes & test(Tmpl<Args...> const &);
    static no & test(...);

    static bool const value = sizeof(test(std::declval<T>())) == sizeof(yes);
};

用法:derives_from_template<T, Base>::value等。

答案 1 :(得分:0)

我认为您可以为B类模板提供标记类型作为成员,并导致一般tempkate的实例化在出现时失败。通常情况下,SFINAE以相反的方式工作,但使用间接方式它仍然可以工作。

template<typename T1, typename T2> 
class Base {
public:
    struct isBase {};
};

template <typename T>
struct is_base {
    template <typename S> char (&test(typename S::isBase*))[1];
    template <typename S> char (&test(...))[2];
    enum { value = sizeof(test<T>(0)) == 1 };
};

template <typename T>
typename std::enable_if<!is_base<T>::value>::type f(T value) {
    ...
};

该解决方案基本上与KerrekSB的解决方案类似,但不需要明确拼写支持的类型:它使用标记isBasd(可能拼写更加独特)来检测{{1}类型的对象或者派生的。