2012-12-16 80 views
2

这个问题的通用模板函数如下这样: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(ok),f(Base<double, double>)会叫version B(ok),但是f(Derived1<double, double, double>)将打电话给version A(请参阅开头的其他问题的链接)。

使用C++ 11,如何阻止version A和力version BBase<T1, T2>任何T1T2所有派生成员是谁?

注意:如果可能,我想避免添加助手类,并希望添加成员到提供的类。

+0

东西是不防火,但在大多数情况下工作,并且很短:http://codepad.org/HkfK7TfQ –

+0

什么是T :: Base?构造函数? (+在什么情况下它不会工作)? – Vincent

+0

当T不通过定义一个名为'Base'的成员来隐藏它时,'T :: Base'是'Base '的继承注入类名。如果'T'本身是'Base ',那么'T :: Base'命名构造函数(但SFINAE注意那么'f'也被忽略)。 –

回答

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

+0

非常好的一段代码。现在,我正在寻找如何在没有特殊类的情况下为我的特定应用程序做同样的事情。 – Vincent

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类型或派生的对象。

+0

你能举一个例子吗,我不确定你在描述什么? – Vincent

+1

在移动设备上输入代码只需要一段时间:-) –