std :: function принимает лямбда-функции с аргументами разного типа передачи (по ref, по val) - PullRequest
0 голосов
/ 21 февраля 2019

пожалуйста, посмотрите на следующий код

#include <iostream>
#include <functional>
#include <string>

int main()
{
    std::function<void(std::string&)> theFunc;
    std::string foo = "0";

    theFunc = [](std::string a) { a = "1";  };  // this compiles but has a different function signature
    theFunc(foo);
    std::cout << "foo should be 1 but is " << foo << std::endl;

    theFunc = [](auto a) { a = "2";  };         // this infers the wrong type for auto(by val not by ref), creates the wrong function signature and compiles 
    theFunc(foo);
    std::cout << "foo should be 2 but is " << foo << std::endl;

    theFunc = [](std::string& a) { a = "3";  };  // this compiles and correctly manipulates the string
    theFunc(foo);
    std::cout << "foo should be 3 and is " << foo << std::endl;

    theFunc = [](auto& a) { a = "4";  };  // this compiles and correctly manipulates the string
    theFunc(foo);
    std::cout << "foo should be 4 and is " << foo << std::endl;

    std::cin.get();
}

В примере кода у нас есть одна std :: function, назначенная различным типам лямбд.

Лямбда 3, которую я понимаю, потому что подпись функциисоответствует.

Но лямбда-1 создает другую сигнатуру функции, но компилируется правильно.

Lambda 2 определяет неправильный тип авто (по val, а не по ref) и правильно компилируется.

Это функция или ошибка?Что я неправильно понимаю относительно класса функций / лямбда-выражений и автоматического определения типа?

ОБНОВЛЕНИЕ:

Спасибо за ответ, Handy999, но почему следующее не компилируется тогда?

    std::function<void(std::string)> theFunc2;

    theFunc2 = [](std::string& a) { a = "1";  };  // this doesn't compile and has a different function signature
    theFunc2(foo);

1 Ответ

0 голосов
/ 21 февраля 2019

В отличие от указателей на функции, std::function принимает все, что может быть вызвано, как указано.При необходимости создается небольшая функция-обертка (в фоновом режиме).

Во всех случаях может быть вызван код

void smallWrapper(std::string& s) {
    ([](std::string a) { a = "1"; })(s);
}

void smallWrapper2(std::string& s) {
    ([](auto a) { a = "2"; })(s);
}

void smallWrapper3(std::string& s) {
    ([](std::string& a) { a = "3"; })(s);
}

void smallWrapper4(std::string& s) {
    ([](auto& a) { a = "4"; })(s);
}

.auto всегда выводит базовый тип, поэтому всегда std::string.Таким образом, случай 2 = случай 1 и случай 4 = случай 3. Это то, что делает std::function и что оно должно делать.


Для пятого случая это действительно так, как указал Калет.Вы не можете позвонить

([](std::string& a) { a = "5"; })("string");

, поскольку не можете привязать ссылку к временному.(Здесь функция-обертка будет работать. Так что это не очень хорошая модель.) Для константных ссылок она работает как обычно:

([](const std::string& a) { a = "6"; })("string");
...