我非常希望能够提供一个仿函数作为模板参数。仿函数必须能够提供“自己”作为那个论点。
我想象这样的事情:
template<typename T, template<typename> class SumFunctor> class foo;
template<typename T>
struct sum_default
{
foo<T, sum_default> operator()(foo<T, sum_default> a, foo<T, sum_default> b) const
{
T a_data = a.data();
T b_data = b.data();
return foo<T, sum_default>(a_data + b_data);
}
};
template<typename T>
struct sum_awesome
{
foo<T, sum_awesome> operator()(foo<T, sum_awesome> a, foo<T, sum_awesome> b) const
{
T a_data = a.data();
T b_data = b.data();
return foo<T, sum_awesome>(a_data - b_data);
}
};
template<typename T=int, template<typename> class SumFunctor=sum_default>
class foo
{
private:
T _data;
SumFunctor<T> _functor;
public:
foo<T, SumFunctor>(T data) : _data(data) {}
T data() { return _data; }
friend const foo operator +(const foo& lhs, const foo& rhs)
{
return lhs._functor(lhs,rhs);
}
};
int main(){
foo<> a(42);
foo<double> b(1.0);
foo<double,sum_default> c(4.0);
foo<double,sum_awesome> d(4.0);
a+a;
d+d;
}
这是可能的,如果是的话,怎么样?
另一种解决方案是为构造函数提供仿函数,但我认为这非常难看,因为用户必须自己动态分配仿函数(因为我们无法确定构造函数中仿函数的类型。使用RTTI来做所以看起来也有点难看):
foo<double> a(42, new sum_default<double>() );
这也强制所有的仿函数都来自一些预定义的基函子。
更新
尝试向sum_default模板参数添加模板参数似乎无法解决问题:
template<typename T>
struct sum_default
{
// Error 1 error C3200: 'sum_default<T>' : invalid template argument for template parameter 'SumFunctor', expected a class template
foo<T, sum_default<T> > operator()(foo<T, sum_default<T> > a, foo<T, sum_default<T> > b) const
{
T a_data = a.data();
T b_data = b.data();
return foo<T, sum_default<T> >(a_data + b_data);
}
};
答案 0 :(得分:3)
你在这里咬什么被称为“类名注入” - 在类模板中,例如Foo<T>
,Foo
的无限制使用实际上被视为Foo<T>
。引用C ++11§14.6.1/ 1:
与普通(非模板)类一样,类模板具有注入类名。 inject-class-name可以用作模板名称或类型名称。当它与 template-argument-list 一起使用时,作为模板 template-parameter 的 template-argument ,或作为最终标识符在友元类模板声明的 elaborated-type-specifier 中,它引用了类模板本身。否则,它等同于 template-name ,后跟
<>
中包含的类模板的 template-parameters 。
因此,在sum_default<T>
内,如果您有foo<T, sum_default>
,则会将其视为您键入的foo<T, sum_default<T> >
(显然无效,因为foo
需要模板模板参数)。
为了避免这种行为,您需要限定在这些类模板中使用类模板名称。由于您的类模板位于全局范围内,因此::
就足够了:
template<typename T>
struct sum_default;
template<typename T = int, template<typename> class SumFunctor = sum_default>
class foo
{
T _data;
SumFunctor<T> _functor;
public:
foo<T, SumFunctor>(T data) : _data(data) { }
T data() { return _data; } const
friend foo operator +(foo const& lhs, foo const& rhs)
{
return lhs._functor(lhs, rhs);
}
};
template<typename T>
struct sum_default
{
foo<T, ::sum_default> operator ()(foo<T, ::sum_default> a,
foo<T, ::sum_default> b) const
{
return foo<T, ::sum_default>(a.data() + b.data());
}
};
template<typename T>
struct sum_awesome
{
foo<T, ::sum_awesome> operator()(foo<T, ::sum_awesome> a,
foo<T, ::sum_awesome> b) const
{
return foo<T, ::sum_awesome>(a.data() - b.data());
}
};
int main()
{
foo<> a(42);
foo<double> b(1.0);
foo<double, sum_default> c(4.0);
foo<double, sum_awesome> d(4.0);
a + a;
d + d;
}
请注意,这也允许您定义foo
的构造函数,从而减少一点噪音:
foo(T data) : _data(data) { }