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

时间:2018-12-14 18:27:31

标签: c++ c++11 c++14

假设我有以下代码:

recvfrom()

两个compute()调用将仅实例化一个函数模板,即compute <1,2,3>还是取决于参数而存在两种不同的实例化?

我想通过使用指向特定实例的函数指针来确认这一点,看看是否可以使用相同的函数指针使用2个不同的参数集调用函数,但是在调用fp的行中出现以下错误(a,b):

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);
}

3 个答案:

答案 0 :(得分:6)

参数包是贪婪的。

&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是不同的类型。

答案 1 :(得分:3)

  

两个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...中的哪个。每个编译器所做的就是将所有参数都包含在第一个包中-因此fp最终成为int(*)(Matrix<1,2,3>, Matrix<>)。换句话说,此版本是采用Matrix<1,2,3>Matrix<>的函数。这与两个原始呼叫都不相同。

事实上,由于两个原始调用是对两个不同函数的调用,因此不可能使用指向两个函数的单个函数指针。相反,您可以做的是构造一个执行正确操作的函数 object

auto fp = [](auto m1, auto m2){ return compute(m1, m2); };

这可以(尝试),但是却是另一回事。

答案 2 :(得分:0)

不同的方法。不需要整数序列或临时函子对象。链接: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
    }

}

更多泛型:https://gcc.godbolt.org/z/EF6OK9支持具有3个Matrix参数的函数。