微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

具有函数、输入和输出类型的可变参数模板

如何解决具有函数、输入和输出类型的可变参数模板

我试图了解如何使用函数、输入参数和输出参数类型创建和调用可变参数模板。我写了这个玩具示例:

#include <tuple>

template<typename Func,typename... Inputs,typename... Outputs>
std::tuple<double,Outputs...> foo(int init,Func&& func,Inputs&&... args) {
    return std::forward<Func>(func)(init,std::forward<Inputs>(args)...);
};

int main () {
    int init = 6;
    double mult = 2.3;
    std::tuple<double,double> bar = foo(
        init,[](int init_,double mult_) { 
            double res = init_ * mult_;
            return std::make_tuple(res,4.1);
        },mult
    );
    int out = std::get<0>(bar);
    return out;
}

但是,它不会编译。我应该如何修改它以获得 13 结果?

我收到此错误消息:

<source>: In function 'int main()':
<source>:11:41: error: conversion from 'tuple<double>' to non-scalar type 'tuple<double,double>' requested
   11 |     std::tuple<double,double> bar = foo(
      |                                      ~~~^
   12 |         init,|         ~~~~~                            
   13 |         [](int init_,double mult_) {
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    
   14 |             double res = init_ * mult_;
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~  
   15 |             return std::make_tuple(res,4.1);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   16 |         },|         ~~                               
   17 |         mult
      |         ~~~~                             
   18 |     );
      |     ~                                    
<source>: In instantiation of 'std::tuple<double,Outputs ...> foo(int,Func&&,Inputs&& ...) [with Func = main()::<lambda(int,double)>; Inputs = {double&}; Outputs = {}]':
<source>:18:5:   required from here
<source>:5:72: error: Could not convert 'main()::<lambda(int,double)>(init,std::forward<double&>((* & args#0)))' from 'tuple<double,double>' to 'tuple<double>'
    5 |     return std::forward<Func>(func)(init,std::forward<Inputs>(args)...);
      |                                                                        ^
      |                                                                        |
      |                                                                        tuple<double,double>

解决方法

你可以把这个模板函数写成:

template<typename Func,typename... Inputs>
auto foo(int init,Func&& func,Inputs&&... args) {
    return std::forward<Func>(func)(init,std::forward<Inputs>(args)...);
}

原始版本的问题在于typename... Outputs,无法推断。您需要明确指定它们 - 但这是不可能的,因为该模板中有两个可变参数包 - 因此无法说明 Inputs... 在哪里结束以及 Outputs 在哪里开始。

或者 - 您可以只指定一个结果类型名称 - 并指定该类型:

template<typename Output,typename Func,typename... Inputs>
Output foo(int init,std::forward<Inputs>(args)...);
}

并调用:

std::tuple<double,double> bar = foo<std::tuple<double,double>>(
        init,[](int init_,double mult_) { 
            double res = init_ * mult_;
            return std::make_tuple(res,4.1);
        },mult
    );

或者将函数模板作为静态函数移动到类模板中:


template<typename ...Output>
struct Foo
{
template <typename Func,typename... Inputs>
static std::tuple<Output...> foo(int init,std::forward<Inputs>(args)...);
}
};


并调用:

auto bar = Foo<double,double>::foo(
        init,mult
    );
,

foo 的主体不可用于推断 Outputs...,因此它们被推断为空。

要强制它返回第一个元素为 std::tupledouble,您可以编写一个特征。

template <typename>
struct is_tuple_of_double : std::false_type {};

template <typename... Others>
struct is_tuple_of_double<std::tuple<double,Others...>> : std::true_type {};

template <typename T>
constexpr bool is_tuple_of_double_v = is_tuple_of_double<T>::value;

template<typename Func,Inputs&&... args) {
    static_assert(is_tuple_of_double_v<decltype(std::forward<Func>(func)(init,std::forward<Inputs>(args)...)>);
    return std::forward<Func>(func)(init,std::forward<Inputs>(args)...);
};

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。