Понимание проблемы
второй параметр (sum
) вашего лямбда-выражения
auto add = [](const int a, int& sum) { sum += a; };
является ссылкой lvalue .
Пакет параметров, ArgsType
в
template <class F, class... ArgsType>
void do_something(F f, ArgsType... args);
выводится в пакет аргументов int
, int
при передаче переменных i
и s
в качестве аргументов соответственно.
Учитывая, что std::forward<ArgsType>(args)...
совпадает с static_cast<ArgsType&&>(args)...
(т. Е. Он просто приводится к типу rvalue ), вызов do_something()
будет эквивалентен вызову следующего шаблон функции:
template <class F>
void do_something(F f, int a, int b)
{
f(static_cast<int&&>(a), static_cast<int&&>(b));
}
Выражение static_cast<int&&>(b)
представляет собой rvalue (точнее, xvalue ). Поскольку вы не можете инициализировать ссылку на lvalue (параметр) значением rvalue (аргумент), это приведет к ошибке компиляции.
Решение
Вы можете использовать переадресацию ссылок вместо:
template <class F, class... ArgsType>
void do_something(F f, ArgsType&&... args);
Тип отдельных аргументов пакета аргументов args
всегда будет ссылкой:
- Тип ссылки lvalue , если в качестве аргумента передано lvalue.
- rvalue ссылочный тип, если в качестве аргумента передано rvalue.
Таким образом, для вашего вызова функции пакет параметров ArgsType
будет выведен в пакет аргументов int&
, int&
, который будет эквивалентен вызову следующего шаблона функции:
template <class F>
void do_something(F f, int& a, int& b)
{
f(static_cast<int& &&>(a), static_cast<int& &&>(b));
}
Поскольку свертывание ссылки применяется к static_cast<int& &&>(b)
, выражение приводит к static_cast<int&>(b)
, что является lvalue. Тип ссылки lvalue может быть инициализирован значением lvalue.
Однако учтите, что звонок:
do_something(add, i, 7);
^
|
--- rvalue
не будет компилироваться сейчас, поскольку rvalue передается в add
в качестве второго аргумента. Рассуждение похоже на исходную ошибку.