Компилятор не может вывести аргументы шаблона для шаблона variadi c - PullRequest
3 голосов
/ 01 апреля 2020

Предположим, я хочу сделать частичное применение функции , чтобы широкий спектр функций соответствовал одной сигнатуре.

Например, я мог бы захотеть go из двойной Функция параметра для функции с одним параметром выглядит следующим образом:

std::function<int(int, int)> doubleFoo = [](int i, int j) { return i + j; };
// Turn the function into a single-parameter function, using j = 5
std::function<int(int)> singleFoo = toSingleFoo(doubleFoo, 5);

Поскольку я хочу, чтобы toSingleFoo обрабатывал любую функцию с одним или несколькими аргументами, первый аргумент которой int, определил его как шаблонную функцию variadi c:

template <typename... Args>
std::function<int(int i)> toSingleFoo(std::function<int(int, Args&&...)> multiFoo, Args&&... args)
{
    auto singleFoo = [args](int i) { multiFoo(i, std::forward<Args>(args)...) };
    return singleFoo;
}

Однако это приводит к следующим ошибкам компилятора (с использованием Visual Studio 2017, версия 15.7.6):

error C2672: 'toSingleFoo': no matching overloaded function found
error C2784: 'std::function<int (int)> toSingleFoo(std::function<int(int,Args &&...)>,Args &&...)':
              could not deduce template argument for 'std::function<int(int,Args &&...)>' 
              from 'std::function<int (int,int)>'

Почему компилятор не может вывести аргументы шаблона, несмотря на то, что int передается в качестве второго аргумента в примере выше?

1 Ответ

2 голосов
/ 01 апреля 2020

Для начала вам нужно захватить multiFoo, а также захватить переменную c args....

Кажется, проблема с вычетом в аргументе std::function. Если вы позволите ему только вывести Args... из второго аргумента, вычет будет продолжаться, как и ожидалось.

Чтобы скрыть вывод первого аргумента, просто поместите его в шаблон идентификации

template<typename T>
struct I { using type = T; };

Затем вы можете определить функцию как

template <typename... Args>
std::function<int(int)> toSingleFoo(
                          typename I<std::function<int(int, Args&&...)>>::type multiFoo, 
                          Args&&... args)
{
    return [multiFoo, &args...] (int i) {
        return multiFoo(i, std::forward<Args>(args)...); 
    };
}

и затем использовать это

int main() {
    std::function<int(int, int)> doubleFoo = [](int i, int j) { return i + j; };
    // Turn the function in a single-parameter function, using j = 5
    std::function<int(int)> singleFoo1 = toSingleFoo(doubleFoo, 5);

    std::cout << singleFoo1(3); // prints 8

    std::function<int(int, int, int)> tripleFoo = [](int i, int j, int k) { return i * j * k; };
    // Turn the function in a single-parameter function, using j = 2, k = 3
    std::function<int(int)> singleFoo2 = toSingleFoo(tripleFoo, 2, 3);

    std::cout << singleFoo2(4); // prints 24
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...