模板:如何使用模板变量控制构造函数参数的数量
templates: how to control number of constructor args using template variable.
我想用这种方式创建一个简单的Vector类(math):
template <int D, typename T = float>
class Vector
{
T m[D];
// ...
};
其中D
为维数。如果是2,则该向量将存储两个类型为T
的值。
如何声明构造函数接受T
类型的D
参数?
Vector<2> v(1.0f, -6.3f);
如何添加一个功能,如果只有D
如果一个特定的数字?如果D
>= 1,我希望添加GetX()
,如果D
>= 2,如果CC_9>= 2,如果D
>= 3,则添加GetZ()
,但以下代码应生成编译时错误:
Vector<2> v(1.0f, -6.3f);
cout << v.GetZ() << endl;
如果D为<1?
我没有遵循什么特定的标准,什么都可以。
所以我提供了一个人们喜欢的有点傻的答案。但这比那简单多了:)
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];
};
您可以使用可变模板和SFINAE来获得具有正确参数数量的构造函数。
构造函数没有返回值,所以我们需要对其中一个参数使用SFINAE。要使用可变模板,我们需要在末尾有参数包。
这意味着我们需要对第一个参数使用SFINAE。
那么这意味着第一个参数之后的参数包需要比维度少一个参数。
有了这个,我们可以写:
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];
};
现在:
v<4, int> a(1,2,3,4); // ok!
v<4, int> b(1,2,3); // error! no such constructor
我没有访问c++ 11编译器,但也许这样的东西可以工作?
#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]; }
};
这有点偏离主题,但也许这将是最少的工作量:使用tuple
。然后,您可以免费获得所有访问器函数。
唯一要做的就是创建一个元组工厂:
template <typename T, unsigned int D> struct tuple_maker
{
typedef typename tcat<T, tuple_maker<T, D - 1>::type>::type type;
}
template <typename T> struct tuple_maker<T, 1>
{
typedef std::tuple<T> type;
}
我们需要辅助tcat
:
template <typename T, typename Tuple> struct tcat;
template <typename T, typename ...Args> struct tcat<T, std::tuple<Args...>>
{
typedef typename std::tuple<T, Args...> type;
}
用法:
tuple_maker<float, 3>::type myVec3D;
使用模板别名,我们可以做得更好:
template <typename T, unsigned int D>
using MyVector = typename tuple_maker<T, D>::type;
MyVector<double, 4> myVec4D;
这应该可以完成工作:
template<int N, typename T>
class Array
{
private:
T Data[N];
public:
template<int i>
void Init() { }
template<int i, typename... Args>
void Init(T Arg0, Args... Rest)
{
Data[i] = Arg0;
Init<i + 1>(Rest...);
}
template<typename... Args>
Array(T Arg0, Args... Rest)
{
static_assert(sizeof...(Args) + 1 == 5, "Wrong number of arguments");
Data[0] = Arg0;
Init<1>(Rest...);
}
};
int main (int argc, const char * argv[])
{
Array<5, int> arr(1, 2, 3, 4, 5);
return 0;
}
如何声明构造函数接受D个类型为T的参数?
你不能那样做。您可以对每个受支持的维度进行专门化,并为每个维度提供适当的构造函数。或者,您可以定义一个构造函数,该构造函数接受多个默认值参数,并忽略那些未使用的参数。或者您可以定义多个构造函数,从1到某个上限,如果参数数量大于D
,则定义static_assert
。
如何添加一个函数只有当D如果一个特定的数字?
这是通过专门化完成的。你必须把所有的公共功能移到一些VectorBase模板中,并从它继承,并在维度上做部分专门化来添加这些功能。
如果D为<1?
或者您可以为基本模板定义所有这些函数,如果D
不足以使用该函数,则可以为static_assert
定义这些函数。不过,现在您只是失去了显式实例化。您还可以为这些函数添加一个虚拟模板参数,这样您就可以使用enable_if
和SFINAE来丢弃函数。
- C++:使用运算符 = 调用多参数构造函数
- 通过零参数构造函数创建的 glm::mat4 应该包含哪些值?
- 好奇的混合与可变参数构造函数
- 具有默认值的单个参数构造函数是否与默认构造函数相同?
- 为什么我们需要创建一个单参数构造函数来使用临时的无名称对象
- 在可变参数构造函数中初始化常量数组
- C++ 显式多参数构造函数歧义
- 零一参数构造函数
- 可变参数构造函数中的 SFINAE
- 当没有显式关键字与单参数构造函数一起使用时,编译器可以发出警告
- 可变参数类模板和可变参数构造函数
- 确保模板参数类型与其可变参数构造函数的类型匹配
- C++默认参数构造函数与内联初始化优先级
- 如何在 c++ 中将包含复制构造函数的类的参数构造函数称为私有?
- 自动存储中没有无参数构造函数的类对象和异常
- 警告:用两个参数构造函数返回对象时,表达结果未使用
- 如何在C++中调用无参数构造函数
- 在 c++ 中具有多个参数构造函数的模板类存在问题
- 可变参数构造函数优先于用户提供的移动构造函数,除非默认
- 如何从可变参数构造函数参数构造任何对象?