std :: function而不是谓词的模板

pau*_*l23 10 c++ templates stl c++11 std-function

许多标准库算法都采用谓词函数.但是,这些谓词的类型是用户提供的任意模板参数.为什么C++ 11没有指定这些类型采用特定类型std::function?例如:

template< class InputIt >
InputIt find_if( InputIt first, InputIt last,
             std::function<bool()> p );
Run Code Online (Sandbox Code Playgroud)

是不是使用这个而不是模板作为参数类型不是更干净?

Nic*_*las 10

std::function用于运行时多态性.任何特定的std::function实例都可以存储任何类型的仿函数(std::function当然,这种仿函数适合于签名).

标准库算法等根据其函数参数的类型进行模板化.因此,他们不需要运行时多态来完成他们的工作; 它们依赖于编译时多态性.

最重要的是,此类算法不需要强制运行时多态性的成本.如果你想要运行时多态,你可以发送它std::function或其他什么.如果你想要编译时多态,你可以为它提供一个不使用多态调度的类型(aka:大多数函子或函数).

运行时多态性的代价还包括无法内联函数调用.使用适当的函子(甚至函数指针,取决于你的编译器有多好),编译器通常可以根据需要内联函数调用.使用运行时多态性,您不仅要支付运行时调度的成本(可能包括额外的参数转发成本),您还将失去重要的优化机会.

  • @LightnessRacesinOrbit:我觉得很明显.模板采用的函数对象类型是模板类型的一部分.因此,模板的每个实例化都可以*在编译时*确切地知道它正在采取什么.多态(调用不同函数的能力)在编译时静态完成.`std :: function`使用runtime-polymorphism.任何特定的`std :: function`对象都可以存储适合其签名的任何类型的函数对象. (6认同)
  • 我同意这个答案.我认为值得一提的是,当传递lambda作为推导模板参数类型的参数时,编译器通常会内联对lambda的调用.他们不会用`std :: function`来做这件事 - 当然,随着编译器对C++ 11的支持的成熟,这可能会有所改进. (4认同)

mas*_*oud 9

性能!

模板基本功能非常好于std::function模式.我为你做了这个测试:

template <typename F>
void test1(const F &f)
{
    for (unsigned long long i = 0; i < 19000000; i++)
        f();
}

void test2(function<void()> &f)
{
    for (unsigned long long i = 0; i < 19000000; i++)
        f();
}

int main()
{
    {
    LARGE_INTEGER frequency, start, end;
    double interval;
    QueryPerformanceFrequency(&frequency);
    QueryPerformanceCounter(&start);

    unsigned long long x = 0;
    test1([&x]()
    {
        x++;
    });

    QueryPerformanceCounter(&end);
    interval = (double) (end.QuadPart - start.QuadPart) / frequency.QuadPart;

    cout << "Template mode: " << interval << " " << x << endl;
    }
    {
    LARGE_INTEGER frequency, start, end;
    double interval;
    QueryPerformanceFrequency(&frequency);
    QueryPerformanceCounter(&start);

    unsigned long long x = 0;
    function<void() > f = [&x]()
    {
        x++;
    };
    test2(f);

    QueryPerformanceCounter(&end);
    interval = (double) (end.QuadPart - start.QuadPart) / frequency.QuadPart;

    cout << "std::function mode:" << interval << " " << x << endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

模板模式:2.13861e-006

std :: function mode:0.220006

Windows7-O2 Core2 Duo CPU 2.40GHz 上的gcc 4.7.2