Не пойму как правильно написать invoke
чтоб компилировалось
#include <iostream>
#include <functional>
struct AA
{
AA()
{
std::cout << "AA::AA()\n";
}
~AA()
{
std::cout << "AA::~AA()\n";
}
AA(const AA&)
{
std::cout << "AA::AA(const AA&)\n";
}
AA(AA&&)
{
std::cout << "AA::AA(AA&&)\n";
}
AA& operator = (const AA&)
{
std::cout << "AA& AA::operator(const AA&)const\n";
return *this;
}
AA& operator = (AA&&)
{
std::cout << "AA& AA::operator(AA&&)\n";
return *this;
}
};
template<class F, typename... Args>
void invoke(F func, Args... args)
{
// Do something before
func(std::forward<decltype(args)>(args)...);
// Do something after
}
int main()
{
AA aa;
std::function<void(AA&)> ff = [](AA& aa) { std::cout << "&aa=" << &aa << "\n";};
invoke(std::move(ff), std::move(aa));
}
Весь цимес в том что мне передают функтор ff который ожидает неконстантный референс на AA, в точке вызова invoke(...) мне не проблема отдать вледение на AA, но вот компилятор с этим не согласен:
2137849079/source.cpp: In instantiation of ‘void invoke(F, Args ...) [with F = std::function<void(AA&)>; Args = {AA}]’: 2137849079/source.cpp:48:40: required from here 2137849079/source.cpp:40:9: error: no match for call to ‘(std::function<void(AA&)>) (AA)’ func(std::forward<decltype(args)>(args)...); ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /usr/include/c++/7/functional:58:0, from 2137849079/source.cpp:2: /usr/include/c++/7/bits/std_function.h:701:5: note: candidate: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = void; _ArgTypes = {AA&}] function<_Res(_ArgTypes...)>:: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ /usr/include/c++/7/bits/std_function.h:701:5: note: conversion of argument 1 would be ill-formed: 2137849079/source.cpp:40:9: error: cannot bind non-const lvalue reference of type ‘AA&’ to an rvalue of type ‘AA’ func(std::forward<decltype(args)>(args)...); ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
UPD
Вторая проблема. При таком вызове
AA aa;
std::function<void(const AA&)> ff = [](const AA& aaa) { std::cout << "&aaa=" << &aaa << "\n";};
invoke(std::move(ff), aa);
где-то вызывается конструктор копирования
> AA::AA()
> AA::AA(const AA&)
> &aaa=0x7fff8eb18faf
> AA::~AA()
> AA::~AA()
По-моему, главная ваша проблема - что ваша ff
принимает lvalue, а впихнуть вы ей пытаетесь rvalue.
Вот такое вроде бы сработает так, как вы хотите - нет?
template<class F, typename... Args>
void invoke(F func, Args... args)
{
// Do something before
func(std::forward<Args>(args)...);
// Do something after
}
int main()
{
AA aa;
std::function<void(AA&&)> ff = [](AA&& aa) { std::cout << "&aa=" << &aa << "\n";};
invoke(std::move(ff), std::move(aa));
}
"По-моему, так..." (с) Пух*
К вашему UPD - зависит от компилятора. VC++ 2019 ничего не копирует...
Собственно проблема в std::forward
, вы пытаетесь запихнуть T в T&. Лямбда не является шаблонной функцией, поэтому использование std::forward
является лишним, так как сохранение типа не требуется. Простая передача обеспечит неявное приведение к T&.
Ещё вы используете std::move
, но при этом принимаете копию в invoke
. К счастью шаблоны считают && за универсальную ссылку, что обеспечивает принятие любых аргументов без копирования.
template<class F, typename... Args>
void invoke(F&& func, Args&&... args)
{
// Do something before
func(args...);
// Do something after
}
Также и при добавлении && к шаблонным аргументам, вы всё равно не сможете использовать std::forward
из-за того, что попытаетесь запихнуть T&& вместо T&. Однако если вы откажетесь от std::move
, тогда у вас получится, копирования всё ещё не произойдёт.
template<class F, typename... Args>
void invoke(F&& func, Args&&... args)
{
// Do something before
func(std::forward<Args>(args)...);
// Do something after
}
int main()
{
AA aa;
decltype(auto) ff = [](AA& aa) { std::cout << "&aa=" << &aa << "\n";};
invoke(ff, aa);
}
Всё таки, я больше склоняюсь ко второму варианту, но если у вас есть веская причина использовать std::move
, то используйте первый.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Как отфильтровать по русскому алфавиту значения одной из нескольких переменной, которые выводятся через цикл foreach?
Помогите разобраться с запросом к API с JWT авторизациейВ идеале пример кода