I'm trying to make a simple Vector class (math) this way:
template <int D, typename T = float>
class Vector
{
T m[D];
// ...
};
Where D
is the number of dimensions. If it is two, the vector will store two values of type T
.
How can I declare the constructor function to take D
arguments of type T
?
Vector<2> v(1.0f, -6.3f);
How to add a function only if D
if a specific number? I wish to add GetX()
if D
is >= 1, GetY()
if D
is >= 2 and GetZ()
if D
is >= 3, but the following code should generate a compile-time error:
Vector<2> v(1.0f, -6.3f);
cout << v.GetZ() << endl;
How to generate a compile-time error if D is < 1?
I'm not following any specific standard, anything will work for me.
There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
There is no difference between using <typename T> OR <class T> ; i.e. it is a convention used by C++ programmers.
Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration.
So I provided a bit of a silly answer that people liked. But this is much easier than that :)
template <int D, typename T = float>
class v {
public:
template <typename... Args>
v(Args... args) : a{ T(args)... } {
static_assert(sizeof...(Args) == D, "wrong number of arguments");
}
private:
T a[D];
};
You can use variadic templates and SFINAE to get a constructor with the right number of parameters.
Constructors don't have return values so we need to use SFINAE on one of the parameters. And to use variadic templates, we'll need to have the parameter pack at the end.
This means we need to use SFINAE on the first parameter.
Then this means the parameter pack after the first parameter needs to have one less parameter than the dimensions.
With this in hand, we can write:
template <int D, typename T>
class v {
public:
template <typename... Tail>
v(typename std::enable_if<sizeof...(Tail)+1 == D, T>::type head, Tail... tail)
: a{ head, T(tail)... } {}
private:
T a[D];
};
And now:
v<4, int> a(1,2,3,4); // ok!
v<4, int> b(1,2,3); // error! no such constructor
I don't have access to a C++11 compiler but maybe something like this could work?
#include <array>
#include <type_traits>
template <int D, typename T>
class Vector
{
static_assert(D > 0, "Dimension must be greater than 0");
std::array<T,D> m;
public:
template<typename... Args>
Vector(Args&&... args) : m{T(args)...}
{
static_assert(sizeof...(Args) == D, "Invalid number of constructor arguments.");
}
T GetX() const { return m[0]; }
T GetY() const { return m[1]; }
T GetZ() const { return m[2]; }
};
template <typename T>
class Vector<1, T>
{
std::array<T,1> m;
public:
Vector(const T& t0) : m{t0}
{
}
T GetX() const { return m[0]; }
};
template <typename T>
class Vector<2, T>
{
std::array<T,2> m;
public:
Vector(const T& t0, const T& t1) : m{t0, t1}
{
}
T GetX() const { return m[0]; }
T GetY() const { return m[1]; }
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With