Functor与模板参数

时间:2010-12-09 00:45:16

标签: c++ performance templates functor

使用带有静态成员函数的模板参数而不是函子式谓词时,是否有任何性能优势?

例如,仿函数风格的排序界面通常是这样的:

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排序例程或类似的东西,只是更一般的仿函数问题的一个例子......

5 个答案:

答案 0 :(得分:4)

正常使用sort不会在堆上放置任何内容,原因很简单,没有人会调用mallocnew。如果您的谓词在其构造函数或比较中调用了mallocnew,那么您只能责怪自己......

将某些堆栈用于_Pred类型的参数是合理的(您不能在代码中调用模板参数_Pred,因为_Pred是保留符号。可以在std::sort)的实现中调用。但除了谓词对象可能具有的任何数据成员所必需的之外,不会有任何相关的工作要做。如果谓词没有数据成员,那么优化器将有一个字段日,如果它有数据成员,那么静态成员函数将不支持用户想要做的事情。

只要谓词中的operator()是非虚拟的,编译器就可以将其内联到sort的实例化中,如果它可以看到定义并且感觉它是最好的。当然不能保证什么更快,但是没有理由认为对静态成员函数的调用比调用非虚拟非静态成员函数更快或更慢,也没有理由更容易或更难内联。

答案 1 :(得分:1)

  

理论上,第一种情况可能   动态创建一个临时函子   堆上的对象,而我相信   第二种情况是完全的   在编译时评估。

第一种情况是在堆栈上创建一个临时的仿函数对象。您是否担心Pred::Pred()是否会分配存储空间?如果是这样,您也可以担心静态函数是否会出于某种原因在堆上分配存储。

无论如何,使用这种习惯用法的大多数谓词仿函数对象都有非常简单的构造函数,因为它们的唯一目的是调用重载的operator (),因此编译器可能会优化对象构造并生成一个简单的构造函数。功能调用。

答案 2 :(得分:0)

在第一种情况下,您可以创建

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 ++编译器会忽略额外的对象创建/破坏,甚至可能内联比较器。

答案 3 :(得分:-1)

如果_Pred::less_than不是虚拟的,则两个解决方案都是相同的,因为编译器确切知道它是什么函数,并且如果需要可以内联。

假设我正确理解你的代码 - 真正的代码会更清晰。我假设代码1执行类似if (less_than.compare(a, b))的操作,代码2执行if (_Pred::less_than(a, b))

编辑:我应该提到示例1会按值传递对象,因此您将承担可能涉及的任何成本(如复制构造函数)。

答案 4 :(得分:-1)

如果我是你,我会不再担心你是否会通过一种方式而不是另一种方式购买微纳秒......并且更担心不使用保留的名称!

在担心像这样的垃圾之前,你还有很长的路要走。当你到达那里的时候......希望你已经知道像这样的废话是毫无意义的。

尽管如此,为了使这个“回答”:两者都没有,你的程序是不正确的。