模板仿函数与函数
Template functors vs functions
我一直在查看一些 Boost 源代码并注意到它们通过使用仿函数而不是普通函数来实现模板化函数?这有什么原因吗?
例如:
template<typename Foo, typename Bar>
struct functor {
Bar operator()(const Foo& foo) {
return foo.as_bar();
}
};
相对于:
template<typename Foo, typename Bar>
Bar func(const Foo& foo) {
return foo.as_bar();
}
我唯一能想到的优点是它允许类继承功能?
主要有两个原因:首先,正如 pythonic 隐喻所指出的,偏特化仅对 类 有效,对函数无效。请注意,函数通常可以使用重载来克服这个问题,但如果您正在进行元编程,通常使用部分特化会更容易和更通用。我实际上认为这是主要原因。
第二个原因是,任何时候代码想要接受一个函数对象(就像在 STL 中,例如 std::transform),它都会有一个类型模板参数。如果你传递一个仿函数或一个 lambda,确切的类型在编译时是已知的,你不需要为间接性付出代价,并且可以执行内联。如果您传递函数指针(或 std::function),则在编译时只有签名是已知的,并且您需要支付间接费用(并且不能内联)。例如,std::sort 使用仿函数比使用函数指针要快得多。
请注意,有一个小功能称为函数指针模板参数;这些是专门针对特定功能的非类型模板参数,因此可以消除间接性。但是,如果您使用其中之一,则根本无法使用函子。因此,大多数想要接受函数对象的代码都按照我上面描述的方式进行。
我一直在查看一些 Boost 源代码并注意到它们通过使用仿函数而不是普通函数来实现模板化函数?这有什么原因吗?
例如:
template<typename Foo, typename Bar>
struct functor {
Bar operator()(const Foo& foo) {
return foo.as_bar();
}
};
相对于:
template<typename Foo, typename Bar>
Bar func(const Foo& foo) {
return foo.as_bar();
}
我唯一能想到的优点是它允许类继承功能?
主要有两个原因:首先,正如 pythonic 隐喻所指出的,偏特化仅对 类 有效,对函数无效。请注意,函数通常可以使用重载来克服这个问题,但如果您正在进行元编程,通常使用部分特化会更容易和更通用。我实际上认为这是主要原因。
第二个原因是,任何时候代码想要接受一个函数对象(就像在 STL 中,例如 std::transform),它都会有一个类型模板参数。如果你传递一个仿函数或一个 lambda,确切的类型在编译时是已知的,你不需要为间接性付出代价,并且可以执行内联。如果您传递函数指针(或 std::function),则在编译时只有签名是已知的,并且您需要支付间接费用(并且不能内联)。例如,std::sort 使用仿函数比使用函数指针要快得多。
请注意,有一个小功能称为函数指针模板参数;这些是专门针对特定功能的非类型模板参数,因此可以消除间接性。但是,如果您使用其中之一,则根本无法使用函子。因此,大多数想要接受函数对象的代码都按照我上面描述的方式进行。