这个问题遵循以下问题: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 A
和version B
是什么,如何阻止Base<T1, T2>
并强制T1
T2
的所有派生成员?
注意:如果可能的话,我想避免添加帮助程序类,而是希望在提供的类中添加成员。
答案 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}类型的对象或者派生的。