简体   繁体   English

具有 function 的可变参数模板,输入和输出类型

[英]Variadic template with function, inputs and outputs types

I'm trying to understand how to create and call variadic templates with function, inpus args and output args types.我试图了解如何使用 function、inpus args 和 output args 类型创建和调用可变参数模板。 I wrote this toy example:我写了这个玩具示例:

#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;
}

However, it doesn't compile.但是,它不会编译。 How should I modify it to get 13 as result?我应该如何修改它以获得13作为结果?

I get this error message:我收到此错误消息:

<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>

You can write this template function as:您可以将此模板 function 编写为:

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

The problem with the original version is with typename... Outputs , they cannot be deduced.原始版本的问题在于typename... Outputs ,它们无法推断。 You would need to specify them explicitly - but this is impossible because there are two variadic packs in that template - so it is impossible to say where Inputs... ends and where Outputs starts.您需要明确指定它们 - 但这是不可能的,因为该模板中有两个可变参数包 - 因此无法说出 Inputs... 的结束位置和 Outputs 的开始位置。

Alternatively - you can just specify one result typename - and specify that type:或者 - 您可以只指定一个结果类型名称 - 并指定该类型:

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

and call:并致电:

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
    );

Or move the function template into class template as static function:或者将 function 模板作为 static ZC1C425268E68385D1AB5074FCC17 移动到 class 模板中


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


and call:并致电:

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

The body of foo isn't available to deduce Outputs... , so they are deduced as empty. foo的主体不可用于推断Outputs... ,因此它们被推断为空。

To enforce that it returns a std::tuple where the first element is double , you can write a trait.要强制它返回第一个元素为doublestd::tuple ,您可以编写一个特征。

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, typename... Inputs>
auto foo(int init, Func&& 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)...);
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM