Ошибка C2280 при сборке с MSVC и пакетом параметров
Имеется код:
#include <iostream>
#include <functional>
#include <future>
#include <deque>
template<class T>
struct Caller;
template<class R, class... Args>
struct Caller<R(Args...)>
{
using PackagedTask = std::packaged_task<R(Args...)>;
using InternalTask = std::packaged_task<void(void)>;
void enque(PackagedTask&& task, Args&&... args)
{
auto fnc = [](auto&& task, auto&&... args) -> void
{ if (task.valid()) task(std::forward<Args>(args)...); };
auto bnd = std::bind(std::move(fnc),
std::forward<PackagedTask>(task),
std::forward<Args>(args)...);
m_tasks.emplace_back(std::move(bnd));
}
void run()
{
if (!m_tasks.empty())
{
auto& task = m_tasks.front();
if (task.valid()) task();
m_tasks.pop_front();
}
}
std::deque<InternalTask> m_tasks;
};
int main()
{
std::packaged_task<int(int)> task
{
[](auto a)
{
std::cout << "tra-ta-ta: " << a << std::endl;
return 5;
}
};
Caller<int(int)> c;
c.enque(std::move(task), 5);
c.run();
}
С компилятором GCC собирается без ошибок, MSVC же выдаёт C2280. Прошу помощи разобраться, что именно ему не нравится и как это можно исправить?
*UPD Судя по всему, проблема связана с этим. И решения нет.
Ответы (1 шт):
Как правильно замечено по ссылке, это баг MSVC компилятора, который пофиксили и запланировали исправить на следующем major релизе.
Как было уже сказано, одно из возможных решений, чтобы обойти это ограничение - это обернуть std::packaged_task в умный указатель (через std::make_shared). Если среди остальных параметров (args) бывают также std::packaged_task объекты, то их тоже надо будет обернуть.
Код ниже работает и под Windows (MSVC) и под Linux (CLang/G++). Только обязательно условие под Linux это добавление опции -pthread, без неё std::packaged_task бросает исключение std::system_error "Unknown error -1".
Рабочий код ниже (оборачивает и task и args):
Попробовать на онлайн Windows MSVC!
Попробовать на онлайн Linux G++/CLang!
#include <iostream>
#include <functional>
#include <future>
#include <deque>
#include <memory>
template<class T>
struct Caller;
template<class R, class... Args>
struct Caller<R(Args...)>
{
using PackagedTask = std::packaged_task<R(Args...)>;
using InternalTask = std::packaged_task<void(void)>;
void enque(PackagedTask&& task, Args&&... args)
{
auto fnc = [](auto&& task, auto&&... args) -> void
{ if (task->valid()) (*task)(std::forward<Args>(*args)...); };
auto bnd = std::bind(std::move(fnc),
std::make_shared<PackagedTask>(std::forward<PackagedTask>(task)),
std::make_shared<Args>(std::forward<Args>(args))...);
m_tasks.emplace_back(std::move(bnd));
}
void run()
{
if (!m_tasks.empty())
{
auto& task = m_tasks.front();
if (task.valid()) task();
m_tasks.pop_front();
}
}
std::deque<InternalTask> m_tasks;
};
int main()
{
std::packaged_task<int(int)> task
{
[](auto a)
{
std::cout << "tra-ta-ta: " << a << std::endl;
return 5;
}
};
Caller<int(int)> c;
c.enque(std::move(task), 5);
c.run();
}