std::函数的模板参数中“const”修饰符和引用的作用是什么

What is the effect of `const` modifier and reference in the template argument of std::function

本文关键字:作用 是什么 引用 函数 参数 std const      更新时间:2023-10-16

我不确定std::函数的模板参数中const修饰符和引用的效果。例如,在以下代码中,我应该使用std::function<bool(std::string, std::string)>还是std::function<bool(const std::string&, const std::string&)>作为基类?我在GCC 4.4中测试了这两个,但是没有区别。提前谢谢。

#include <iostream>
#include <functional>
#include <string>
//struct FLess : public std::function<bool(std::string, std::string)>
struct FLess : public std::function<bool(const std::string&, const std::string&)>
{
    bool operator () (const std::string& s1, const std::string& s2) const
    {
        return s1 < s2;
    }
};
int main(int argc, char* argv[])
{
    FLess f;
    std::string a = "a";
    std::string b = "b";
    std::cerr << f(a, b) << std::endl;
    return 0;
}

您不应该从std::function继承。

相反,您可以使用以下方法来抽象底层函数对象:

void DoSomething(function<void(const string&, const string&) myF)
{
    string s1, s2;
    myF(s1, s2);
}
// usage:
DoSomething(bind(otheFunc, ....));
DoSomething([](const string& s1, const string& s2) { ... });
struct Func
{
    operator()(const string& s1, const string& s2)
    { ... }
}
Func f;
DoSomething(f);

现在来回答您的问题,如果您使用const string&,则要求编译器不要复制对象并禁止修改。这个选择取决于你对参数的意义。

对于像数字和小型结构这样的小型类型,通过复制传递。

除非您想执行非常高级的复制/移动优化,否则对于大型类型,最好始终使用const&。我认为string是一种大型,除非你确信它永远不会生长。

如果函数的参数类型可以转换为可调用实体的参数类型,则函数对象的参数类型与其引用的可调用实体参数类型之间的兼容性:

void foo(double x, double y);
void bar(const double& x, const double& y);
void fooBar(double& x, double& y);
std::function<void(const double&, const double&)> f;
f = &foo; // OK
f = &bar; // OK
f = &fooBar; // Error on GCC 4.7. Cannot instantiate a double& from const double.

有趣的是,具有void返回类型的std::函数与具有任何返回类型的可调用实体都兼容:

int fooBarFoo(const double& x, const double& y);
f = &fooBarFoo; // OK

因此,在您的情况下,比较通过const引用传递和通过值传递,我认为没有明显的差异。

传递对const对象的引用可以避免只为传递给函数而复制对象。在你的情况下(一个小字符串),它可能没有足够的区别来引起注意。

如果您处理的是一个(比如)几兆字节的字符串,通过引用传递给const可以避免为所有数据分配空间(和复制)。

同时,大多数编译器内部实现的引用非常像指针。由于额外的间接级别,这可能会导致执行速度减慢。对于小项目(char、int,可能是long),您通常更喜欢按值传递。对于较大的项目(可能是长字符串、矩阵等),您通常更喜欢通过引用传递。如果有疑问,通常通过参考——在这个方向上出错的惩罚通常相当小。