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

#include <iostream>
#include <future>

std::size_t calc_something(std::size_t lim_)
{   
    std::size_t result = lim_ * 10;
    return result;
}

void calc_something(std::size_t lim_, std::promise<std::size_t> &promise_)
{   
    std::size_t result = lim_ * 10;
    promise_.set_value(result);
}

void async_calc()
{
    std::future<std::size_t> async_calc = std::async(calc_something, 5);
    std::cout<< "async_calc = " << async_calc.get() <<std::endl;
}

Я все еще плохо знаком с многопоточностью, но почему - на земле, - std::async не может выбрать правильную перегрузку? Вторая перегрузка использует ссылку на объект std::promise.

Я смотрел на этот вопрос здесь, но он не объясняет почему. Кроме того, я не получаю ошибку неоднозначности.

Ошибка, которую я получаю:

error: no matching function for call to 'async' std::future<std::size_t> async_calc = std::async(calc_something, 5);
2
Constantinos Glynos 3 Фев 2020 в 18:03

2 ответа

Наборы перегрузки не могут быть отправлены как параметр как есть, они должны быть сначала преобразованы в указатель функции или должны быть переданы в объект.

Наборы перегрузки должны быть преобразованы, поскольку только имя функции обозначает полный набор функций, но вы должны отправить только одну из них. То, как компилятор выберет правильный, зависит от аргументов, которые вы ему отправили. Вызов этого параметра предоставляет тип параметров, но преобразование в указатель на функцию также предоставляет компилятору достаточно информации о том, какая перегрузка должна быть отправлена.

Преобразование в указатель на функцию обычно является простым способом:

auto function = static_cast<std::size_t(*)(std::size_t)>(calc_something);
std::future<std::size_t> async_calc = std::async(function, 5);

Подъем осуществляется с помощью лямбды:

std::future<std::size_t> async_calc = std::async([](auto lim) { return calc_something(lim); }, 5);

Подъем здесь возможен, так как вы вызываете набор перегрузки, поэтому есть параметр, который может выбрать компилятор.

Он просто не может отложить это решение для наборов перегрузки, но для лямбда-функции и шаблона может.

1
Guillaume Racicot 3 Фев 2020 в 18:06

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

std::future<std::size_t> async_calc = std::async(calc_something, 5);

В приведенном выше коде какая перегрузка будет передана std::async()?

std::size_t calc_something(std::size_t);
void calc_something(std::size_t, std::promise<std::size_t> &);

Вы должны указать:

std::async(static_cast<std::size_t(*)(std::size_t)>(calc_something), 5);
2
Nicol Bolas 3 Фев 2020 в 16:10