在可变参数函数内的不同参数包中推导出两个不同的已知类型变量
deduce two different known type variables in different parameter packs within a variadic function
我有以下代码:
template <typename... Type1, typename... Type2>
void foo(const Type1&&... t1, Type2&&... t2)
{
int len = sizeof...(Type1);
cout << len << endl;
int len1 = sizeof...(Type2);
cout << len1 << endl;
}
int main()
{
foo(1, 2, 4.5, 5.5);
return 0;
}
调用 foo()
将 Type1
推断为空,将 Type2
推断为 {int, int, double, double}
,而我想要的是 Type1
作为 {int, int}
和 Type2
为 {double, double}
。是否可以不涉及 std::tuple
并像我在上面的代码中那样调用 foo()
函数?
编辑:
为了更清楚地说明我要实现的目标,这里有一个解释。我想创建一个函数,用户可以在其中每次以偶数对传递任意数量的两种类型变量。假设 foo(Type1 x, Type1 y, Type1 z, Type1 ..., Type2 XX, Type2 YY, Type2 ZZ, Type2 ...);
Type1
的变量将始终是 const
引用,而 Type2
的变量只是引用,因此函数最终将具有以下形式:foo(const Type1& x, const Type1& y, ..., Type2& XX, Type2& YY, ...)
.在函数中,我将使用 Type1
变量应用一些计算,并通过 Type2
变量应用 return 相应的结果。我知道使用任何容器结构都会让我的生活更轻松,但不幸的是我无法采用该解决方案。因此,尽管我不是经验丰富的人,但我认为使用可变参数函数是可行的方法,对吗?
不,编译器无法读懂你的想法。
您可以将一组类型分成两半:
template<class...>struct types{using type=types;};
template<class lhs, class rhs>struct cat;
template<class lhs, class rhs>using cat_t=typename cat<lhs,rhs>::type;
template<class...lhs, class...rhs>
struct cat<types<lhs...>,types<rhs...>>:
types<lhs...,rhs...>
{};
template<class types, size_t n>
struct split {
private:
using s0 = split<types,n/2>;
using r0 = typename s0::lhs;
using r1 = typename s0::rhs;
using s1 = split<r1,n-n/2>;
using r2 = typename s1::lhs;
public:
using lhs = cat_t<r0,r2>;
using rhs = typename s1::rhs;
};
template<class Types>
struct split<Types, 0>{
using lhs=types<>;
using rhs=Types;
};
template<class T0,class...Ts>
struct split<types<T0,Ts...>,1>{
using lhs=types<T0>;
using rhs=types<Ts...>;
};
然后我们用它来将 foo
参数分成两个包:
template<class types>
struct foo2_t;
template<class... T0s>
struct foo2_t<types<T0s...>>{
template<class... T1s>
void operator()(T0s&&... t0s, T1s&&... t1s) const {
std::cout << sizeof...(T0s) << '\n';
std::cout << sizeof...(T1s) << '\n';
}
};
template <class... Ts>
void foo(Ts&&... ts) {
using s = split< types<Ts...>, sizeof...(Ts)/2 >;
foo2_t<typename s::lhs>{}( std::forward<Ts>(ts)... );
}
如果您希望编译器执行不同的魔术(例如,集中在相同的类型上,或者您想到的任何其他类型),则可以使用不同的(但相似的)技术。
尝试更简单的方法。
以两个向量作为参数。
template<typename T, typename A>
void foo( std::vector<T,A> const& t1, std::vector<T,A> const& t2 ) {
//do wtever you want
}
我有以下代码:
template <typename... Type1, typename... Type2>
void foo(const Type1&&... t1, Type2&&... t2)
{
int len = sizeof...(Type1);
cout << len << endl;
int len1 = sizeof...(Type2);
cout << len1 << endl;
}
int main()
{
foo(1, 2, 4.5, 5.5);
return 0;
}
调用 foo()
将 Type1
推断为空,将 Type2
推断为 {int, int, double, double}
,而我想要的是 Type1
作为 {int, int}
和 Type2
为 {double, double}
。是否可以不涉及 std::tuple
并像我在上面的代码中那样调用 foo()
函数?
编辑:
为了更清楚地说明我要实现的目标,这里有一个解释。我想创建一个函数,用户可以在其中每次以偶数对传递任意数量的两种类型变量。假设 foo(Type1 x, Type1 y, Type1 z, Type1 ..., Type2 XX, Type2 YY, Type2 ZZ, Type2 ...);
Type1
的变量将始终是 const
引用,而 Type2
的变量只是引用,因此函数最终将具有以下形式:foo(const Type1& x, const Type1& y, ..., Type2& XX, Type2& YY, ...)
.在函数中,我将使用 Type1
变量应用一些计算,并通过 Type2
变量应用 return 相应的结果。我知道使用任何容器结构都会让我的生活更轻松,但不幸的是我无法采用该解决方案。因此,尽管我不是经验丰富的人,但我认为使用可变参数函数是可行的方法,对吗?
不,编译器无法读懂你的想法。
您可以将一组类型分成两半:
template<class...>struct types{using type=types;};
template<class lhs, class rhs>struct cat;
template<class lhs, class rhs>using cat_t=typename cat<lhs,rhs>::type;
template<class...lhs, class...rhs>
struct cat<types<lhs...>,types<rhs...>>:
types<lhs...,rhs...>
{};
template<class types, size_t n>
struct split {
private:
using s0 = split<types,n/2>;
using r0 = typename s0::lhs;
using r1 = typename s0::rhs;
using s1 = split<r1,n-n/2>;
using r2 = typename s1::lhs;
public:
using lhs = cat_t<r0,r2>;
using rhs = typename s1::rhs;
};
template<class Types>
struct split<Types, 0>{
using lhs=types<>;
using rhs=Types;
};
template<class T0,class...Ts>
struct split<types<T0,Ts...>,1>{
using lhs=types<T0>;
using rhs=types<Ts...>;
};
然后我们用它来将 foo
参数分成两个包:
template<class types>
struct foo2_t;
template<class... T0s>
struct foo2_t<types<T0s...>>{
template<class... T1s>
void operator()(T0s&&... t0s, T1s&&... t1s) const {
std::cout << sizeof...(T0s) << '\n';
std::cout << sizeof...(T1s) << '\n';
}
};
template <class... Ts>
void foo(Ts&&... ts) {
using s = split< types<Ts...>, sizeof...(Ts)/2 >;
foo2_t<typename s::lhs>{}( std::forward<Ts>(ts)... );
}
如果您希望编译器执行不同的魔术(例如,集中在相同的类型上,或者您想到的任何其他类型),则可以使用不同的(但相似的)技术。
尝试更简单的方法。 以两个向量作为参数。
template<typename T, typename A>
void foo( std::vector<T,A> const& t1, std::vector<T,A> const& t2 ) {
//do wtever you want
}