我正在尝试编写一个函数模板。对于不满足其他版本标准的所有类型,应使用一个版本;当参数是给定类的基类或该类本身时,应使用另一个版本。
我曾尝试为Base&
执行重载,但是当类派生自Base
时,它们使用的是普通的,而不是特定的。
我也尝试过这种SFINAE方法:
struct Base { };
struct Derived : public Base { };
struct Unrelated { };
template<typename T>
void f(const T& a, bool b = true) {
cout << "not special" << endl;
}
template<typename T>
void f(const Base& t, bool b = is_base_of<Base, T>::value) {
cout << "special" << endl;
}
Base b;
Derived d;
Unrelated u;
f(b); f(d); f(u);
但他们所有人都打印“不特别”。我不擅长SFINAE,我可能只是做错了。我怎么写这样的函数?
答案 0 :(得分:3)
首先,这些都不会调用“特殊”f
重载,因为T
无法从函数参数中推断出来。它的第一个参数必须是T
类型:
void f(const T& t, bool b = is_base_of<Base, T>::value)
完成后,请注意“特殊”重载并不真正使用SFINAE来影响重载分辨率:is_base_of<T, U>::value
总是有一个值:它是true
或false
。要影响重载分辨率,您需要使用enable_if
,它有条件地根据布尔值定义类型。
此外,两个重载都需要使用SFINAE:如果从基数派生T
(或者是基类型),则必须启用“特殊”重载,并且必须仅启用“非特殊”重载如果T
不是从基数派生的,否则会出现重载决策模糊。
应声明两个重载并将其定义为:
template<typename T>
void f(T const& a, typename enable_if<!is_base_of<Base, T>::value>::type* = 0)
{
cout << "not special" << endl;
}
template<typename T>
void f(T const& t, typename enable_if<is_base_of<Base, T>::value>::type* = 0)
{
cout << "special" << endl;
}
最后,请注意这里没有专业化。这两个名为f
的函数是重载。
答案 1 :(得分:2)
这是一个简单的C ++ 03方法:
namespace detail // implementation details, users never invoke these directly
{
template<bool B>
struct f_impl
{
template<typename T>
static void f(T const& t) { std::cout << "not special\n"; }
};
template<>
struct f_impl<true>
{
static void f(Base const& t) { std::cout << "special\n"; }
};
}
template<typename T>
void f(T const& t)
{
detail::f_impl<is_base_of<Base, T>::value>::f(t);
}
答案 2 :(得分:0)
重载的一种方法是:
#include <iostream>
using namespace std;
struct Base { };
struct Derived : public Base { };
struct Unrelated { };
void f(...) {
cout << "not special" << endl;
}
void f(const Base& t) {
cout << "special" << endl;
}
int main(){
Base b;
Derived d;
Unrelated u;
f(b);
f(d);
f(u);
return 0;
}
结果:
special
special
not special
采用变量参数列表的重载将采用任何类型的参数,但总是被认为不适合任何其他可用的重载。