简体   繁体   中英

Is it possible to write a static variadic template function, in a template class, that's able to take N parameters of type T?

I'm having trouble writing the variadic function that:

1) takes the appropriate number of parameters N-1 (N always > 2) of the appropriate type FooArray<T, N> and

2) allows me to play with them in the fiddly way I need to.

So, given the following template class:

template <typename T, unsigned int N>
class FooArray{
private:
    T m_data[N];
};

and the following static variadic template function declaration:

template <typename T, unsigned int N>
class FooArray{
public:
    template <typename ... ArgT>
    static FooArray<T, N> Weirdness(FooArray<T, N> _arg1, ArgT ... _args);
private:
    T m_data[N];
};

and associated implementation in that class:

template <typename T, unsigned int N>
template <typename ... ArgT>
FooArray<T, N>
FooArray<T, N>::Weirdness(T _arg1, ArgT ... _args)
{
    static_assert(N > 2, "Not enough Ns for Weirdness.");
    static_assert(N - 2 == sizeof... (_args), "Incorrect parameter number.");

    FooArray<T, N> result;
    // ...
    // Put parameters into table of size N * (N-1) maybe?
    // Do stuff with that to determine result.
    // ...
    return result;
}

I want to have the given code (or something like it) return me errors at the marked places and be valid in the marked places too.

int main()
{
    FooArray<int, 2> test2parameter;
    FooArray<int, 3> test3param1, test3param2;
    FooArray<int, 4> test4p1, test4p2, test4p3;

    //FooArray<int, 2>::Weirdness(test2parameter); // Should error(and does), not enough N's.

    //FooArray<int, 3>::Weirdness(); // Should error(and does), requires 2 parameters.
    //FooArray<int, 3>::Weirdness(test2parameter); // Should error(and does), requires 2 parameters of type FooArray<int, 3>.
    FooArray<int, 3>::Weirdness(test3param1, test2parameter); // Should error(currently doesn't), all parameters should be FooArray<int, 3>.
    FooArray<int, 3>::Weirdness(test3param1, test3param2); // Valid.

    //FooArray<int, 4>::Weirdness(); // Should error (and does), requires 3 parameters.
    //FooArray<int, 4>::Weirdness(test4p1, test4p2); // Should error (and currently does), requires 3 parameters.
    FooArray<int, 4>::Weirdness(test4p1, test4p2, test3param1); // Should error (currently doesn't), all parameters should be FooArray<int, 4>.
    FooArray<int, 4>::Weirdness(test4p1, test4p2, test4p3); // Valid.

    //FooArray<int, 12>::Weirdness(test12p1, test12p2, test12p3, test12p4, test12p5, test12p6, test12p7, test12p8, test12p9, test12p10, test12p11); // Will be a valid case.

    return 0;
}

Re: the initial question, I'm 90% there. Once I have the compiler throwing errors at me for passing the function an incorrect parameter type, the question is answered.

Thank you for your time. (Seriously, stop reading now if you're short on time or are trying to solve your own problem)

Re: Why would you want to do this? I am trying to write an N-Dimensional vector (geometry) cross product function, because I think mathematicians are silly for thinking 3D vectors are the only ones that can have a cross product. I'm certain I can do it if I can write this function. Plus, I'm an indie game developer, this function has interesting uses for me in a handful of games I've got kicking around in my brain.

Bonus material: I have another problem that using variadic templates creates for me. Once I have all these FooArrays inside my Weirdness() function, I have to do a calculation that requires (for every member in the return variable) access to two different members of every passed parameter. So perhaps this is a poor design choice? I'm considering a recursive private static variadic template function to perhaps populate a static array of Ts of size N*(N-1). The existing function doesn't allow this fine fiddle I require. This design bit is all very open ended though and perhaps warrants another question on a more open-ended-question friendly platform. :)

Add one more static assertion:

static_assert(are_same<FooArray<T, N>, ArgT...>::value, "Types do not all match");

And implement are_same<> :

template <typename A1, typename A2, typename ... Rest>
struct are_same
{
  enum { value = std::is_same<A1, A2>::value && are_same<A2, Rest...>::value };
};

template <typename A1, typename A2>
struct are_same<A1, A2>
{
  enum { value = std::is_same<A1, A2>::value };
};

I would prefer a simpler function declaration and using John Zwinck's method to ensure the parameter types are all correct.

template <typename T, unsigned int N>
template <typename ... ArgT>
FooArray<T, N>
FooArray<T, N>::Weirdness(ArgT ... _args)
{
    static_assert(are_same<FooArray<T, N>, ArgT...>::value, "Types do not all match");
    static_assert(N > 2, "Not enough Ns for Weirdness.");
    static_assert(N - 1 == sizeof... (_args), "Incorrect parameter number.");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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