编译器无法推断可变参数模板的模板参数

问题描述 投票:2回答:1

假设我想执行partial function application以使各种功能都符合单个签名。

例如,我可能希望从双参数函数变为单参数函数,如下所示:

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)> singleFoo = toSingleFoo(doubleFoo, 5);

由于我希望toSingleFoo处理第一个参数为int的任何单参数或多参数函数,因此我将其定义为可变参数模板函数:

template <typename... Args>
std::function<int(int i)> toSingleFoo(std::function<int(int, Args&&...)> multiFoo, Args&&... args)
{
    // Changing the capture to [args...], [multiFoo, args], or [multiFoo, args...]
    // as suggested in a now-deleted answer, does not change the compiler error.
    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作为第二个参数传递,但为什么编译器无法推导模板参数?

c++ c++11 variadic-templates
1个回答
0
投票

首先,您需要捕获multiFoo,以及捕获可变参数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)
{
    auto singleFoo = [multiFoo, &args...](int i) { return multiFoo(i, std::forward<Args>(args)...); };
    return singleFoo;
}

然后使用它

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)> singleFoo = toSingleFoo(doubleFoo, 5);

    std::cout << singleFoo(3); // prints 8
}
© www.soinside.com 2019 - 2024. All rights reserved.