2

这个问题跟在这个问题后面:函数重载和模板推导优先级

考虑以下类:

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(ok),f(Base<double, double>)会调用version B(ok),但f(Derived1<double, double, double>)会调用version A(请参阅开头的另一个问题的链接)。

使用C ++ 11,如何阻止version A和强制version B所有派生成员和是Base<T1, T2>什么?T1T2

注意:如果可能的话,我想避免添加辅助类,而是更喜欢将成员添加到提供的类中。

4

2 回答 2

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

于 2012-12-16T14:09:19.490 回答
0

我认为您可以为您B的类模板提供一个标记类型作为成员,并导致一般模板的实例化在存在时失败。通常,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(可能应该拼写更独特)来检测类型Base或派生的对象。

于 2012-12-16T14:09:40.900 回答