Reputation: 7925
This is a continuation off of this original question here: Original Question that was focused more towards a design decision. This question is more to the actual how to towards the implementation if it can even be done.
I have this in my current source:
template <typename ClassType,typename... Dimensions>
class DimensionPack {
public:
typename std::tuple<ClassType, std::tuple<Dimensions...> >::type Dim;
const unsigned int numarguments = sizeof...(Dimensions);
};
That would be used with a series of classes that are related with the following prototypes:
template<typename ClassType, typename... Args> class MatrixReference;
template<typename ClassType, typename... Args> class MatrixStorage;
template<typename ClassType, typename... Args> class MatrixAllocation;
I have already been asked why couldn't I just use std::size_t...
After considerable thought I'm still leaning towards using the variadic parameter pack with the helper template that would store it into an std::tuple
to help pack and unpack the parameters. Also I have a need to test these parameters to be in the range of {x; x > 0}
so they must all be + integers. So the parameter pack itself or the contents of it can be either std::size_t
or unsigned int
but they all need to be one or the other. I also need to test these parameters to check if their value is even or odd and to save those results into a container. The use of a helper function will do that for me.
Knowing this I'm leaning towards staying with the parameter pack so I can easily pass that pack as a reference from one template to another since the set of these templates will work together, and I can also pass the parameter pack to my helper function to test for odd and even values.
So the questions become:
<typename... Args>
be restricted to a specific type such as std::size_t
or unsigned int
?Upvotes: 1
Views: 708
Reputation: 50568
Can a parameter pack with be restricted to a specific type such as std::size_t or unsigned int?
The bool trick does it in a compact way.
As a minimal, working example:
#include <type_traits>
#include <utility>
template<typename... Args>
constexpr bool check(Args&&...) {
return std::is_same<
std::integer_sequence<bool, true, (std::is_same<std::size_t, std::remove_reference_t<Args>>::value or std::is_same<unsigned int, std::remove_reference_t<Args>>::value)...>,
std::integer_sequence<bool, (std::is_same<std::size_t, std::remove_reference_t<Args>>::value or std::is_same<unsigned int, std::remove_reference_t<Args>>::value)..., true>
>::value;
}
int main() {
static_assert(check(std::size_t{42}, 3u), "!");
static_assert(not check(std::size_t{42}, 'c'), "!");
}
I used both the types in the check because of your comment (emphasis mine):
So the parameter pack itself or the contents of it can be either std::size_t or unsigned int but they all need to be one or the other
See it running on wandbox.
Note that you can use the same technique to check statically the types used to initialize a class.
As an example:
template<typename... Args>
struct S {
static_assert(std::is_same<
std::integer_sequence<bool, true, (std::is_same<std::size_t, std::remove_reference_t<Args>>::value or std::is_same<unsigned int, std::remove_reference_t<Args>>::value)...>,
std::integer_sequence<bool, (std::is_same<std::size_t, std::remove_reference_t<Args>>::value or std::is_same<unsigned int, std::remove_reference_t<Args>>::value)..., true>
>::value, "!");
};
In this case, something like this will compile:
S<std::size_t, unsigned int> s;
On the other side, the following will end with an error at compile time:
S<std::size_t, char> s;
Upvotes: 2