[英]Instantiation of function template with variadic parameter pack
假设我说这个代码:
template<int... Us>
struct Matrix{};
template<int... U1, int... U2>
auto compute(Matrix<U1...>, Matrix<U2...>){return 0;}
Matrix<1> a; Matrix<2,3> b;
Matrix<1,2> c; Matrix<3> d;
int main(){
compute(a,b);
compute(c,d);
auto fp = &compute<1,2,3>;
fp(a,b);
fp(c,d);
}
两个compute()调用是否只实例化一个函数模板,即计算<1,2,3>,还是会有两个不同的实例,具体取决于参数?
我想通过获取一个指向特定实例的函数指针来确认这一点,看看我是否可以使用相同的函数指针调用具有2个不同参数集的函数,但是我在调用fp的行中得到以下错误(a, b):
[x86-64 gcc 8.2 #1] error: could not convert 'a' from 'Matrix<#'nontype_argument_pack' not supported by dump_expr#<expression error>>' to 'Matrix<#'nontype_argument_pack' not supported by dump_expr#<expression error>>'
参数包很贪婪。
&compute<1,2,3>
在伪代码中, &compute< U1={1,2,3}, U2={} >
。
获取指向各个计算的指针很烦人。
template<class U1s, class U2s>
struct get_computer;
template<int...U1, int...U2>
struct get_computer<std::integer_sequence<int, U1...>, std::integer_sequence<int, U2...>> {
using compute_type = int(*)(Matrix<U1...>, Matrix<U2...>);
compute_type operator()() const { return compute; }
};
我们可以做
auto fp1 = get_computer<std::integer_sequence<int, 1>, std::integer_sequence<int, 2, 3>>{}();
auto fp2 = get_computer<std::integer_sequence<int, 1, 2>, std::integer_sequence<int, 3>>{}();
和fp1
和fp2
是不同的类型。
两个
compute()
调用是否只实例化一个函数模板,即compute<1,2,3>
还是会有两个不同的实例,具体取决于参数?
非常不同。 编写compute(a, b)
时调用的函数是一个采用Matrix<1>
和Matrix<2,3>
的函数。 编写compute(c, d)
时调用的函数是一个采用Matrix<1,2>
和Matrix<3>
的函数。
但是当你写这个:
auto fp = &compute<1,2,3>;
没有办法说出U1...
或U2...
哪一个U2...
这些值是指的。 每个编译器所做的是将所有参数都塞进第一个包中 - 所以fp
最终成为一个int(*)(Matrix<1,2,3>, Matrix<>)
。 换句话说,此版本是一个采用Matrix<1,2,3>
和Matrix<>
的函数。 这与两个原始呼叫都不同。
事实上,由于两个原始调用是对两个不同函数的调用,因此不可能将单个函数指针指向它们。 你可以做的是构造一个能做正确事情的函数对象 :
auto fp = [](auto m1, auto m2){ return compute(m1, m2); };
这是有效的(试一试),但却是一种非常不同的东西。
不同的方法。 不需要整数序列或临时仿函数对象。 链接: https : //gcc.godbolt.org/z/W4V6gf
template<int... V1>
struct Mat1 {
template<int... V2>
struct Mat2 {
using compute_type = int(*)(Matrix<V1...>, Matrix<V2...>);
};
};
void foo() {
{
using compute_type = Mat1<1>::Mat2<2,3>::compute_type;
compute_type ct = compute;
ct(a, b);
//ct(c, d); //This wont compile
}
{
using compute_type = Mat1<1,2>::Mat2<3>::compute_type;
compute_type ct = compute;
ct(c, d);
//ct(a, b); //This wont compile
}
}
甚至更通用
template<int... Us>
struct Matrix{};
Matrix<1> a; Matrix<2,3> b;
Matrix<1,2> c; Matrix<3> d;
template<int... U1, int... U2>
auto compute(Matrix<U1...>, Matrix<U2...>){return 0;}
template<class Scalar, template<Scalar...> class MatType>
struct VArg {
template<Scalar... V1>
struct arg1 {
using type = MatType<V1...>;
template<Scalar... V2>
struct arg2 {
using type1 = type;
using type2 = MatType<V2...>;
};
};
};
template<class args_gen>
struct compute_type {
using type = int(*)(typename args_gen::type1, typename args_gen::type2);
};
void foo() {
using int_matrix_gen = VArg<int, Matrix>;
{
using args_ab = int_matrix_gen::arg1<1>::arg2<2,3>;
compute_type<args_ab>::type cptr = compute;
cptr(a, b);
//cptr(c, d); This wont compile
}
{
using args_cd = int_matrix_gen::arg1<1,2>::arg2<3>;
compute_type<args_cd>::type cptr = compute;
cptr(c, d);
//cptr(a, b); This wont compile
}
}
更多Generic'er: https ://gcc.godbolt.org/z/EF6OK9支持具有3个Matrix参数的函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.