包含多个包的c ++模板,按参数推导和返回值

时间:2015-08-09 14:35:47

标签: c++ templates c++11

我有点困惑c ++如何解释以下代码:

template<class ... ReturnTypes, class ... ParameterTypes>
std::tuple<ReturnTypes...> Method(const ParameterTypes & ... Parameters)
{
    (...)
};

编译以下代码时:

std::tuple<unsigned int> R = Object.Method<unsigned int, unsigned int>(10);

我得到了:

error: conversion from 'std::tuple<unsigned int, unsigned int>' to non-scalar type 'std::tuple<unsigned int>' requested
  std::tuple<unsigned int> R = Object.Method<unsigned int, unsigned int>(10);

是否有可能创建一个具有两个参数包的模板方法(在非模板类中) - 一个用于返回类型(在元组中)和一个用于参数类型?

4 个答案:

答案 0 :(得分:1)

您可以使用模板模板参数来区分两个参数包:

#include <tuple>

template <class... T> struct typelist { };

template <typename... ReturnTypes,
          template <typename...> class T,
          class ... ParameterTypes>
std::tuple<ReturnTypes...> Method(T<ReturnTypes...>,
                                  const ParameterTypes & ... Parameters)
{
    return std::tuple<ReturnTypes...>();
};

int main()
{
    using ReturnTypes = typelist<int, char>;
    auto t = Method(ReturnTypes{}, 10, "hello", false);

    static_assert(std::is_same<decltype(t), std::tuple<int,char>>{}, "types do not match");
    return 0;
}

live on ideone

答案 1 :(得分:1)

一种解决方案是使用虚拟类来分隔类型,使用辅助类来获得正确的Method

template<typename...> class type_pack;

template<typename...> class MethodHelper;

template<typename ... ReturnTypes, typename ... ArgTypes>
class MethodHelper<type_pack<ReturnTypes...>, type_pack<ArgTypes...>>{
    public:
        static_assert(
            sizeof...(ReturnTypes) == sizeof...(ArgTypes),
            "number of return types not the same as argument types"
        );

        static auto Method(ArgTypes ... args){
            return std::tuple<ReturnTypes...>(args...);
        }
};

template<typename ReturnPack, typename ArgsPack, typename ... Args>
auto Method(Args &&... args){
    return MethodHelper<ReturnPack, ArgsPack>::Method(std::forward<Args>(args)...);
}

然后你几乎可以像以前一样使用它:

auto main() -> int{
    auto t = Method<type_pack<int, int>, type_pack<size_t, size_t>>(5, 6);
}

或者使用别名让每个人的生活更轻松:

auto main() -> int{
    static constexpr auto &&my_method = Method<type_pack<int, int>, type_pack<float, float>>::Method;

    auto my_tuple = my_method(1.234f, 5.678f);
}

答案 2 :(得分:1)

我不喜欢您选择的语法,因为它不是很清楚哪些参数与函数参数对齐,哪些参数与返回值对齐。

我可以看到3种方法。

首先,保持语法:

template<class...TypeParams, class...Args>
auto Method( Args&&... args )
-> // magic

这很棘手,但是我们可以做一些工作来从sizeof...(TypeParams)-sizeof...(Args)中提取第一个TypeParams参数,并将其作为返回类型元组,并将剩余的args...转换为拖尾集TypeParams

很多工作,你得到了一个糟糕的语法。我通过了。

第二种方法是明确传递包类型:

template<class...>class types_t{using type=types_t; constexpr types_t(){}};
template<class...Ts>constexpr types_t<Ts...> types={};
template<class T>class tag{using type=T;};
template<class Tag>using type_t=typename Tag::type;
template<class T>using block_deduction=type_t<tag<T>>;

template<class... Return, class... Args>
std::tuple<Return...> Method(
  types_t<Return...> ret_types, types_t<Args...> arg_types,
  block_deduction<Args>... args
)

我们这样称呼Method

auto result = Method( types<double>, types<double>, 3 );

我们将两个类型包作为显式type_t<?...>参数传递。我们不推断任何类型,因为你的args的C ++类型可能不符合你想要编组的SQL类型。

最终方法将涉及两次通过解决方案。你的args是一个捆绑:对待它们就像它:

template<class...RetTypes, class...Parms>
std::tuple<RetTypes> Method( std::tuple<Params...> args )

使用:

auto result = Method<double>( std::tuple<double>(3) );

我们将类型捆绑到std::tuple个参数中。这是由Method推断出来的,但可以通过std::tuple 外部的Method构建明确显示。Method。传递给public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new asyncExample().execute("Hello"); } private class asyncExample extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... params) { System.out.print("Enter number of rows in A: "); int rowsInA = 10; System.out.print("Enter number of columns in A / rows in B: "); int columnsInA = 10; System.out.print("Enter number of columns in B: "); int columnsInB = 10; int[][] a = new int[rowsInA][columnsInA]; int[][] b = new int[columnsInA][columnsInB]; System.out.println("Enter matrix A"); for (int i = 0; i < a.length; i++) { for (int j = 0; j < a[0].length; j++) { a[i][j] = 10; } } System.out.println("Enter matrix B"); for (int i = 0; i < b.length; i++) { for (int j = 0; j < b[0].length; j++) { b[i][j] = 10; } } int[][] c = multiply(a, b); System.out.println("Product of A and B is"); for (int i = 0; i < c.length; i++) { for (int j = 0; j < c[0].length; j++) { System.out.print(c[i][j] + " "); } System.out.println(); } return null; } } public int[][] multiply(int[][] a, int[][] b) { int rowsInA = a.length; int columnsInA = a[0].length; // same as rows in B int columnsInB = b[0].length; int[][] c = new int[rowsInA][columnsInB]; for (int i = 0; i < rowsInA; i++) { for (int j = 0; j < columnsInB; j++) { for (int k = 0; k < columnsInA; k++) { c[i][j] = c[i][j] + a[i][k] * b[k][j]; } } } return c; } @Override protected void onPostExecute(String result) { } } 的类型仅 返回类型。

live example

答案 3 :(得分:0)

此解决方案利用了C ++ 14的功能,但为您提供了所需的语法:

#include <utility>
#include <tuple>
#include <cstddef>

template <typename...> struct typelist {};
template <typename T> struct identity { using type = T; };

template <class... Ts, class... Us>
auto Method3(typelist<Ts...>, typelist<Us...>, const typename identity<Us>::type&... parameters)
    -> std::tuple<Ts...>
{
    // (...)
    return {};
}

template <class... Ts, class... Params, std::size_t... Is, std::size_t... Js>
auto Method2(std::index_sequence<Is...>, std::index_sequence<Js...>, Params&&... parameters)
    -> decltype(auto)
{
    return Method3(typelist<typename std::tuple_element<Is, std::tuple<Ts...>>::type...>{}
                 , typelist<typename std::tuple_element<sizeof...(Is) + Js, std::tuple<Ts...>>::type...>{}
                 , std::forward<Params>(parameters)...);
}

template <class... Ts, class... Params>
auto Method(Params&&... parameters)
    -> decltype(auto)
{
    return Method2<Ts...>(std::make_index_sequence<sizeof...(Ts) - sizeof...(Params)>{}
                        , std::make_index_sequence<sizeof...(Params)>{}
                        , std::forward<Params>(parameters)...);
}

int main()
{
    std::tuple<int, short, float> R = Method<int, short, float, double, bool>(3.14, true);
}

DEMO