Каков эффект модификатора const и ссылки в аргументе шаблона std :: function - PullRequest
0 голосов
/ 13 марта 2012

Я не уверен насчет эффекта модификатора const и ссылки в аргументе шаблона std :: function.Например, в следующих кодах я должен использовать 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;
}

Ответы [ 3 ]

3 голосов
/ 13 марта 2012

Вы не должны наследовать от 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 большой тип, если вы не уверены, что он никогда не будет расти.

1 голос
/ 13 марта 2012

Это сводится к совместимости между типами параметров объекта функции и теми вызываемыми объектами, на которые он ссылается, если типы параметров функции могут быть преобразованы в типы параметров вызываемых объектов или нет:

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.

Интересно, что std :: function с возвращаемым типом void совместим с вызываемыми объектами с любым типом возврата:

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

f = &fooBarFoo; // OK

Так что в вашем случае, когда вы сравниваете передачу по константной ссылке, а не передачу по значениюЯ думаю, что нет заметной разницы.

0 голосов
/ 13 марта 2012

Передача ссылки на константный объект позволяет избежать копирования объекта просто для передачи в функцию. В вашем случае (крошечная строка) это, вероятно, не имеет достаточного значения, чтобы заметить.

Если вы имели дело со строкой (скажем) нескольких мегабайт, передача по ссылке на const позволит избежать выделения места (и копирования) всех этих данных.

В то же время большинство компиляторов внутренне реализуют ссылки почти так же, как указатели. Это может привести к замедлению выполнения из-за дополнительного уровня косвенности. Для небольших предметов (char, int, вероятно long) вы обычно предпочитаете передавать по значению. Для более крупных элементов (потенциально длинные строки, матрицы и т. Д.) Вы обычно предпочитаете передавать по ссылке. В случае сомнений обычно переходят по ссылке - штраф за неправильную работу в этом направлении, как правило, довольно небольшой.

...