Yun Huang
Yun Huang

Reputation: 4386

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

I am not sure about the effect of const modifier and reference in the template argument of std::function. For example, in the following codes, should I use std::function<bool(std::string, std::string)> or std::function<bool(const std::string&, const std::string&)> as the base class ? I tested both in GCC 4.4, however, there was no difference. Thanks in advance.

#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;
}

Upvotes: 0

Views: 977

Answers (3)

juanchopanza
juanchopanza

Reputation: 227370

It boils down to compatibility between the function object's parameter types and those of the callable entity it is referring to, if the function's parameter types can be converted to the callable entities parameter types or not:

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.

Interestingly, an std::function with void return type is compatible with callable entities with any return type:

int fooBarFoo(const double& x, const double& y);

f = &fooBarFoo; // OK

So in your case, where you are comparing passing by const reference as opposed to passing by value, I think there is no observable difference.

Upvotes: 1

J.N.
J.N.

Reputation: 8421

You are not supposed to inherit from std::function.

Rather you use to abstract the underlying kind of function object like this:

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);

Now to answer your question, if you use const string& you are asking the compiler not to copy the object and to forbid modifications. That choice depends on the meaning you are giving to your parameters.

For small types like numbers and small struct, pass by copy.

Unless you want to perform very advanced copy/move optimizations, you'd better always use const& for large types. I'd consider string a large type, unless you are sure that it will never grow.

Upvotes: 3

Jerry Coffin
Jerry Coffin

Reputation: 490058

Passing a reference to a const object avoids making a copy of the object just to pass to the function. In your case (a tiny string) it probably doesn't make enough difference to notice.

If you were dealing with a string of (say) several megabytes, passing by reference to const would avoid allocating space for (and copying) all that data.

At the same time, most compilers internally implement references pretty much like pointers. This can lead to slower execution because of an extra level of indirection. For small items (char, int, probably long) you usually prefer to pass by value. For larger items (potentially long strings, matrices, etc.) you usually prefer to pass by reference. If in doubt, usually pass by reference -- the penalty for being wrong in this direction is generally fairly small.

Upvotes: 0

Related Questions