【问题标题】:Compiler unable to deduce template arguments for variadic template编译器无法推断可变参数模板的模板参数
【发布时间】:2020-04-01 19:42:45
【问题描述】:

假设我想做partial function application 以使各种函数符合单个签名。

例如,我可能想从一个双参数函数转到一个单参数函数,如下所示:

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 的单参数或多参数函数,因此我将其定义为可变参数模板函数:

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 作为第二个参数传递?

【问题讨论】:

    标签: c++ c++11 variadic-templates


    【解决方案1】:

    首先,您需要捕获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)
    {
        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
    }
    

    【讨论】:

    • 成功了,谢谢!您是如何提出身份模板解决方案的?这是已知的模式吗?
    • 没错,实际上是c++20中的coming
    • 啊,type_identity can be used to establish non-deduced contexts in template argument deduction。有用的说明:)
    • 据我所知,这就是它的全部目的 :)
    • 延伸阅读:'Template argument deduction' at cppreference.com 的“非推断上下文”部分
    猜你喜欢
    • 2020-01-21
    • 1970-01-01
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 2013-02-18
    • 1970-01-01
    相关资源
    最近更新 更多