繁体   English   中英

使用可变参数包实例化函数模板

[英]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>>{}();

fp1fp2是不同的类型。

两个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.

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