Class method with number of arguments specified by integer template parameter - c++

Was not exactly sure how to phrase this question or what to search on so if this is the same as another question please close and redirect to the appropriate question.
Suppose
template<typename Type, int Size> class vector
{
Type data[Size];
}
Is it possible to replace a constructor which takes Size number of arguments in template specializations like this
template<typename Type> class vector3<Type,3>
{
Type data[3];
public:
vector3( Type, Type, Type );
}
with something in the non-specialized template class? Like a "varargs constructor" that produces a constructor with Size number of arguments of type Type?
A solution involving C++0x features is fine.

In C++0x you have template typedef finally available!
Disclaimer: nothing has been compiled...
From Wikipedia's article:
template< typename second>
using TypedefName = SomeType<OtherType, second, 5>;
which in your case would yield
template <class Type>
using vector3 = vector<Type, 3>;
I can't tell you how much I craved for this ;)
However it doesn't solve the parameters issue. As mentioned, you could try and use variadic templates here, however I am unsure as to their application in this case. The normal use is with recursive methods and you would need to throw a static_assert in the midst.
Edited to take the comments into account.
template <class Type, size_t Size>
class vector
{
public:
template <class... Args>
vector(Args... args): data({args...})
{
// Necessary only if you wish to ensure that the exact number of args
// is passed, otherwise there could be less than requested
BOOST_MPL_ASSERT_RELATION(sizeof...(Args), ==, Size);
}
private:
T data[Size];
};
Another possibility that is already available is to combine Preprocessor generation with boost::enable_if.
template <class Type, size_t Size>
class vector
{
public:
vector(Type a0, typename boost::enable_if_c< Size == 1 >::type* = 0);
vector(Type a0, Type a1, typename boost::enable_if_c< Size == 2 >::type* = 0);
// ...
};
Using Boost.Preprocessor for the generation makes this easier.
BOOST_PP_REPEAT(MAX_COUNT, CONSTRUCTOR_MACRO, ~);
// where MAX_COUNT is defined to the maximum size you wish
// and CONSTRUCTOR_MACRO actually generates the constructor
#define CONSTRUCTOR_MACRO(z, n, data) \
vector( \
BOOST_PP_ENUM_PARAMS(n, Type a), \
typename boost::enable_if_c< Size == n >::type* = 0 \
);
The implementation of the constructor is left as an exercise for the reader. It's another call to BOOST_PP_REPEAT.
As you can see, it soon gets ugly, so you'll be better off if you can use the variadic template version.

There's a further solution to your problem: Using variadic template parameters in the initializer list
template<typename T, unsigned int N>
struct vector {
T data[N];
template<typename... Args>
vector(Args... args) : data({args...}) { }
};
However the number of arguments only needs to be less or equal than N and their types only needs to be convertible to T.

Is it possible to replace a constructor which takes Size number of arguments in template specializations like this
Not without a ton of repetitive, mechanical code, and the maximum size will be limited by the number of times you repeat yourself. Case in point: boost::tuple (which might have exactly the functionality what you want).
In C++0x this won't be a problem thanks to variadic templates.

First you should consider using std::array. It doesn't meet all your requirements but it's close enough that if the differences don't matter you can save yourself a lot of work. The problem is this cheap version will have construct that accepts 2 arguments as well as 3.
template< typename T>
using Vector3 = std::array<T,3>;
Vector3 v1{1,2,3};
Vector3 v2{1,2}; // it sounds like you want to disallow this case.
Otherwise you can create a custom class that acts a lot like std::array, except with a more picky constructor.
template<typename T, std::size_t SIZE>
class Vector
{
public:
template< typename ... Args >
Vector( Args ... args ) :
data({args...})
{
static_assert( sizeof...(Args) == SIZE,
"Incorrect number of arguments passed to Vector constructor");
}
/* lots of extra code here to add std::array -like methods */
private:
// could use std::array here as well.
T data[3];
};
template< typename T >
using Vector3 = Vector<T,3>;
Vector3 v1(1,2,3);
Vector3 v2(1,2); // error at compile time.

Related

Variadic template parameter pack to accept only unsigned ints or size_t as its type

I'm trying to use a set of template classes with a variadic parameter. I have several options ahead of me that I could choose from. Before any of my templates are declared or defined I currently have these prototypes: I'm familiar with templates but I haven't had much experience with variadic types when working with templates so the syntax does get a little confusing to me at times. Being that they are all empty shells they do currently compile.
template<typename ClassType, typename... Args> class MatrixReference;
template<typename ClassType, typename... Args> class MatrixStorage;
template<typename ClassType, typename... Args> class MatrixAllocation;
I have a User End Class that will use these classes depending on the intentions of use; it is currently an empty shell for now until I get the other classes defined correctly with the appropriate behavior:
template<typename ClassType, typename... Args>
class Matrix {
};
The rest of the class from the prototypes shown above will inherit from a base class so that the above user class will have a container of them such that the container would be: std::vector<std::unique_ptr<MatrixBase>> or std::vector<shared_ptr<MatrixBase>> and the vector will only ever contain 1 of each type from the listed prototypes. For instance vector[0] would contain a MatrixStorage, vector[1] would container a MatrixReference and vector[2] would contain a MatrixAllocation. Each of these classes have different responsibilities as their names suggest. The storage class will contain a raw stack copy of the elements. The reference class will be use to reference those copies. The allocation class will be used when the elements are declared on the heap. The base class looks like this:
template <typename ClassType = void>
class MatrixBase {
protected:
MatrixBase(){}
virtual ~MatrixBase(){}
}; // Matrix
I have also thought about inheriting them from a non template base as this class does nothing but serve the purpose of being able to store different class types into a single container. I may go ahead and change this to a non template type but for now I'm using it as is to stay with the conventions of its derived types.
Now onto the declaration of my class templates: I really only need to use one of them here since all follow the same pattern, but I'll show all 3 anyway since they are currently empty shells.
// Stores All Of The Contents Of The Matrix
template<typename ClassType, typename... Args>
class MatrixStorage : public MatrixBase<ClassType> {
}; // MatrixStorage
// Used To Reference The Storage Class Of The Matrix
template<typename ClassType, typename... Args>
class MatrixReference : public MatrixBase<ClassType> {
}; // MatrixReference
// Used Only When User Wants To Create A Matrix On The Heap
template<typename ClassType, typename... Args>
class MatrixAllocation : public MatrixBase<ClassType> {
}; // MatrixAllocation
The design approach that I'm looking for is that when this class is used it follows the pattern where the first type is always the type of data the matrix will store either it be an int, float, or some other user defined type; the next parameter is where the use of a variadic parameter comes in so that if one instantiates a template as such:
Matrix<float,2,2> mat2x2; // Default constructor making it empty
This will generate a 2x2 sized Matrix of floats
Matrix<int,3,3,3> mat3x3x3;
This would generate a 3x3x3 volumetric matrix of ints
So the variadic template part will always be + integers and the minimal requirement would be Matrix<type, 1> where this would be in a sense a scalar or a single element matrix or a 1x1 matrix.
This is where I'm presented with a few options. I could use the following
size_t... N
unsigned... D
typename... Args
Currently at the moment as you can see it is declared with the last of the choices. So now comes the main question:
If I decided to use the Parameter Pack where I have a helper class as such:
template <typename ClassType,typename... Dimensions>
class DimensionPack {
public:
typename std::tuple<ClassType, std::tuple<Dimensions...> >::type Dim;
const unsigned int numarguments = sizeof...(Dimensions);
};
The question becomes; is there a known way to make the Variadic Parameter of the same type namely either size_t or unsigned int? If so an example would be appreciated or a reference link would help as well; I've searched and haven't found anything helpful that is similar enough to help me through this.
If there isn't I don't mind having to use size_t or unsigned int but I was preferring to be able to use the helper template to pack and unpack the variadic parameters for me this way I don't have to implement that in each and every class.
I also have a 2 other derived classes not shown here but one would be used with logging them to the screen, where the other would be used with reading and parsing from a file and writing out to a file.
Also as a side note: For extremely large data sets or extremely large sized Matrices: I also have this helper class to use for them:
template<typename ClassType, std::size_t bufferSize>
class MatrixBuffer {
static std::vector<ClassType> matrixBuffer = std::vector<ClassType>().reserve( bufferSize );
};
Edit
I forgot to add this to the original question but I'm adding it now for a little more clarity. I do have a need to test each variadic parameter's value to see if it is odd or even and the results of them will be stored into a vector with a size of the amount of parameters storing a 0 for even or a 1 for odd. This is one of the reasons why I was leaning towards the use of a parameter pack because I could just pass it to a helper function that would return back the vector that is needed.
std::size_t... Args and typename... Args are not the same. The first would expect integers like
Matrix<float,2,2> mat2x2;
while the second would expect types instead.
Of course, you could use std::integral_constant, but that'd be more verbose:
template <std::size_t N>
using size = std::integral_constant<std::size_t, N>;
Matrix<float,size<2>,size<2>> mat2x2;
On the other hand you could use std::index_sequence:
template<typename ClassType, std::size_t... Dims>
class Matrix {
using Dimensions = std::index_sequence<Dims...>;
};
Using static_assert it is possible to check at compile time :
template <typename ClassType,typename... Dimensions>
class DimensionPack {
public:
DimensionPack(const Dimensions&... args){
checkType<Dimensions...>(args...);
}
~DimensionPack(){}
private:
template<typename T> void checkType(const T& t) {
static_assert(std::integral_constant<bool, std::is_same<T, size_t>::value>(), "T is not of type size_t");
}
template<typename T, typename... V> void checkType(const T& t, const V&... v) {
static_assert(std::integral_constant<bool, std::is_same<T, size_t>::value>(), "T is not of type size_t");
checkType<V...>(v...);
}
};

Variable number of constructor parameters depending on integer template

I'm writing a container storage class template that wraps a private std::array in order to add some functionality to it. The template parametrises the number of values, as follows:
template<size_t N> class Vector {
private:
array<double, N> vals;
public:
[...]
};
I'd like the constructor for the class to only accept N doubles to fill the array, but I can't find a good way to do this. Variadic arguments don't provide a mechanism to check how many of them there are, so they're right out. Parameter packs don't do floating-point promotion, but I'd be willing to deal with that if I could only figure out how to use them for this.
I've tried following the approach in the answer to Member function template with the number of parameters depending on an integral template parameter but I can't understand the significance enable_if<>::type=0 section. I've tried naïvely copying that code in (though I'd much rather understand how it works. I've seen people use ::value in other places but I can't find any documentation on why) but expanding the resulting parameter pack doesn't seem to work. My other concern with parameter packs is that I'm not sure that they'd ensure the types of all arguments were the same.
I've tried running a static_assert on the size of an initializer list, in the body of the constructor, but of course the size of the list is not constant at compile time, so that doesn't work either.
Is there a standard approach here? Am I just using parameter packs wrong?
Update:
I've got the approach in the answer I linked above partly working:
template<size_t N> class Vector {
private:
array<double, N> vals;
public:
template <typename ...T,
typename enable_if<sizeof...(T) == N, int>::type = 0>
Vector(T ...args) {
vals = {args...};
}
};
The issue is now that the enable_if term in the template means that when I initialise a Vector with, for example,
Vector<3> V {1.0, 2.0, 3.0};
It requests a template specialisation Vector<3>::Vector<double, double, double, 0> rather than <double, double, double>. How do I get rid of this stray term in the template?
Don't get what you mean by this:
Variadic arguments don't provide a mechanism to check how many of
them there are, so they're right out
template <typename ...T>
Vector(T... args) {
static_assert(sizeof...(args) <= N, "oops");
}
Should work..
You could additionally generate a pack of the right size via some template specialization tricks:
template <size_t N, class = std::make_index_sequence<N>>
class Vector;
template <size_t N, size_t... Is>
class Vector<N, std::index_sequence<Is...>>
{
private:
std::array<double, N> vals;
template <size_t >
using double_ = double;
public:
Vector(double_<Is>... vals)
{
...
}
};
That is a non-template constructor which takes N doubles.
By following Member function template with the number of parameters depending on an integral template parameter and Variadic templates with exactly n parameters, have got it working with the following code.
template<size_t N> class Vector {
private:
array<double, N> vals;
public:
template <typename ...T,
typename enable_if<sizeof...(T) == N, int>::type = 0>
Vector(T ...args) : vals{args} {}
};

Is there a way to check std::initializer_list number of arguments at compile-time?

I am trying to create a function that would accept several arguments of a given type, but both type and number of arguments should be specified via templates.
I found that using C++11's initializer_list is probably a good technique in this case, but is it possible to check its size at compile time? Are there any other tecnhiques that can solve this problem?
#include <initializer_list>
// Here I want to define type and number of components for each point
template <typename T, int DIM>
class Geometry
{
public:
void addPoint(std::initializer_list<T> coords)
{
assert(coords.size() == DIM); // Working good, but not compile-time
// Next line does not compile because size() is not known at compile-time
static_assert(coords.size() == DIM, "Wrong number of components");
}
};
You cannot statically assert on a runtime quantity. And the number of values in an initializer_list is decided at runtime, by the caller of the function.
Not even making your function constexpr would work, since evaluation of the function is not required to take place at compile-time.
You should instead use a variadic template.
Thanks to Nicol, I looked towards the variadic templates. The problem was not only to check the number of arguments, but also to check that their types are convertible to the base type. Here's my solution based on this and this topics. It works as expected in GCC 4.9.
template<class T, class...>
struct are_convertible : std::true_type
{};
template<class T, class U, class... TT>
struct are_convertible<T, U, TT...>
: std::integral_constant<bool, std::is_convertible<T,U>{} && are_convertible<T, TT...>{}>
{};
template <typename T, int DIM>
class Geometry
{
public:
template<typename... Args>
void addPoint(Args... coords)
{
static_assert(sizeof...(coords) == DIM, "Number of components does not match template");
static_assert(are_convertible<T, Args...>{}, "All arguments' types must be convertible to the template type");
}
};
Adding a POD class Point with DIM data members wout suit your purpose best. Then the implicit constructor call would make sure that everything was OK.

variadic templates same number of function arguments as in class

How to define method signature so it will accept same number of arguments as variadic template class definition? For example how to define an Array class:
template<typename T, int... shape>
class Array
{
public:
T& operator () (???);
};
So you will be able to call it like this:
Array<int, 3, 4, 5> a;
a(1, 2, 3) = 2;
template<class T, int...Shape>
class Array {
template<int>using index_t=int; // can change this
public:
T& operator()(index_t<Shape>... is);
};
or:
template<class T, int...Shape>
class Array {
public:
T& operator()(decltype(Shape)... is);
};
or:
template<class T, int...Shape>
class Array {
public:
T& operator()(decltype(Shape, int())... is);
};
if you want to be able to change the type of the parameter to be different than Shape.
I find the decltype harder to understand a touch than the using, especially if you want to change the type of the parameter to be different than int.
Another approach:
template<class T, int...Shape>
class Array {
public:
template<class...Args,class=typename std::enable_if<sizeof...(Args)==sizeof...(Shape)>::type>
T& operator()(Args&&... is);
};
which uses SFINAE. It does not enforce that the Args are integer types however. We could add another clause if we wanted to (that all of the Args are convertible to int, say).
Yet another approach is to have your operator() take a package of values, like a std::array<sizeof...(Shape), int>. Callers would have to:
Array<double, 3,2,1> arr;
arr({0,0,0});
use a set of {}s.
A final approach would be:
template<class T, int...Shape>
class Array {
public:
template<class...Args>
auto operator()(Args&&... is) {
static_assert( sizeof...(Args)==sizeof...(Shapes), "wrong number of array indexes" );
}
};
where we accept anything, then generate errors if it is the wrong number of arguments. This generates very clean errors, but does not do proper SFINAE operator overloading.
I would recommend tag dispatching, but I don't see a way to make it much cleaner than the SFINAE solution, with the extra decltype and all, or better error messages than the static_assert version on the other hand.
I assume you want your arguments to be all of the same type, probably using an integer type (I'll just use int). An easy approach is to leverage the parameter pack you already have:
template <int>
struct shape_helper { typedef int type; };
template <typename T, int... Shape>
class Array
{
public:
T& operator()(typename shape_helper<Shape>::type...);
};

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.");