[英]Functor vs template parameters
使用带有静态成员函数的模板参数而不是函子式谓词时,是否有任何性能优势?
例如,仿函数风格的排序界面通常是这样的:
template <typename _Type, typename _Pred>
void sort (
RandomAccessIterator first,
RandomAccessIterator last ,
_Pred less_than
)
{
// actual sorting code here, calling less_than()...
}
你可以做更像这样的事情,并要求_Pred
包含一个静态成员函数_Pred::less_than
:
template <typename _Type, typename _Pred>
void sort (
RandomAccessIterator first,
RandomAccessIterator last
)
{
// actual sorting code here, calling _Pred::less_than()...
}
从理论上讲,第一种情况可能会在堆上动态创建一个临时的仿函数对象,而我认为第二种情况在编译时是完全评估的。 我知道(比方说)gcc和/或msvc擅长优化,但在第一种情况下可以做到相同程度吗?
此外,我不是要重写STL排序例程或类似的东西,只是一个更一般的仿函数问题的例子......
正常使用sort
不会在堆上放任何东西,原因很简单,没有人调用malloc
或new
。 如果你的谓词导致对malloc
或new
的调用,无论是在构造函数中还是在比较中,那么你只能责怪自己...
有些堆栈将用于_Pred
类型的参数是_Pred
(您不能在代码中调用模板参数_Pred
,因为_Pred
是一个保留符号。可以在std::sort
的实现中调用它)。 但除了谓词对象可能具有的任何数据成员所必需的之外,不会有任何相关的工作要做。 如果谓词没有数据成员,则优化器将具有字段日,如果它具有数据成员,则静态成员函数将不支持用户想要执行的操作。
只要谓词中的operator()
是非虚拟的,编译器就可以将其内联到sort
的实例化中,如果它可以看到定义并且感觉它是最好的。 当然不能保证什么更快,但是没有理由认为对静态成员函数的调用比调用非虚拟非静态成员函数更快或更慢,也没有理由更容易或更难排队。
从理论上讲,第一种情况可能会在堆上动态创建一个临时的仿函数对象,而我认为第二种情况在编译时是完全评估的。
第一种情况是在堆栈上创建一个临时的仿函数对象。 您是否担心Pred::Pred()
是否会分配存储空间? 如果是这样,您也可以担心静态函数是否会出于某种原因在堆上分配存储。
无论如何,使用这种习惯用法的大多数谓词仿函数对象都有非常简单的构造函数,因为它们的唯一目的是调用重载的operator ()
,因此编译器可能会优化对象构造并生成一个简单的函数调用。
在第一种情况下,您可以创建一个
template<class T>
struct CompareByIntProperties {
CompareByIntProperties(vector<T::*int> props) : props_(props) {}
bool less_than(const T& a, const T& b) const {
for (vector<T::*int>::const_iterator it = props_.begin();
it != props_.end(); ++it) {
if (a.(**it) < b.(**it)) return true;
if (a.(**it) > b.(**it)) return false;
}
return false;
}
vector<T::*int> props_;
};
这会让你
vector<Foo::*int> properties;
if (compare_foo) properties.push_back(&Foo::foo);
if (compare_bar) properties.push_back(&Foo::bar);
if (compare_qux) properties.push_back(&Foo::qux);
sort(container.begin(), container.end(), CompareByIntProperties<Foo>(properties));
请原谅任何语法错误,这些都没有经过编译检查。 但是你明白了。
在第二种情况下,因为你正在调用静态方法,所以你没有自由的统治来自定义这样的比较器。
我不担心效率。 如果你没有访问任何非静态的东西,一个好的C ++编译器将忽略额外的对象创建/破坏,甚至可能内联比较器。
如果_Pred::less_than
不是虚拟的,则两个解决方案都是相同的,因为编译器确切知道它是什么函数,并且如果需要可以内联。
假设我正确理解你的代码 - 真正的代码会更清晰。 我假设代码1执行if (less_than.compare(a, b))
,而代码2执行if (_Pred::less_than(a, b))
。
编辑:我应该提到示例1将按值传递对象,因此您将承担可能涉及的任何成本(如复制构造函数)。
如果我是你,我会不再担心你是否会通过一种方式而不是另一种方式购买微纳秒......并且更担心不使用保留的名称!
在担心像这样的垃圾之前,你还有很长的路要走。 当你到达那里的时候......希望你已经知道像这样的废话是毫无意义的。
虽然,为了使这个“答案”:你的程序也不是很糟糕。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.