我有点困惑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);
是否有可能创建一个具有两个参数包的模板方法(在非模板类中) - 一个用于返回类型(在元组中)和一个用于参数类型?
答案 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;
}
答案 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) {
}
}
的类型仅 返回类型。
答案 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);
}