简单 class 中的常数整数特征
Constant integer trait in simple class
给定下面的简单声明,是否可以给 class 一个常量整数特征来指定组件的数量(在本例中为 2)? Vec3 和 Vec4 分别有 3 和 4。我只想将其作为编译时常量,以各种方式实例化其他模板。它不必在运行时存在。
template<class T>
struct Vec2
{
typedef T value_type;
typedef unsigned index_type;
struct
{
T x, y;
};
};
标准库中已经有两个解决这个问题的方法。
std::array<type, size>
是一种类型的固定大小数组,它具有一个 size() 成员函数、开始和结束迭代器以及一个 [] 运算符。
std::tuple<types...>
给出可以通过索引索引的不相交类型的向量:get<i>(tuple)
或类型 get<typename>(tuple)
.
编辑:
这是一种可能的解决方案:
#include <iostream>
#include <type_traits>
#include <utility>
#include <array>
template<class Type, size_t Size>
struct my_vector
{
static constexpr size_t num_components = Size;
template<class...Args, typename = std::enable_if_t< (sizeof...(Args) == Size) > >
my_vector(Args&&...args) : _data { std::forward<Args>(args)... } {}
template<size_t I >
Type get() const {
return _data[I];
}
std::array<Type, Size> _data;
};
template<class Type, size_t Size, size_t I, class VectorType = my_vector<Type, Size>, typename = void>
struct get;
template<class Type, size_t Size, size_t I >
struct get<Type, Size, I, my_vector<Type, Size>, std::enable_if_t<I <= Size> >
{
static Type apply(const my_vector<Type, Size>& v) {
return v.get<I>();
}
};
template<class Type, size_t Size>
Type x(const my_vector<Type, Size>& v)
{
return get<Type, Size, 0, my_vector<Type, Size>>::apply(v);
}
template<class Type, size_t Size>
Type y(const my_vector<Type, Size>& v)
{
return get<Type, Size, 1, my_vector<Type, Size>>::apply(v);
}
template<class Type, size_t Size>
Type z(const my_vector<Type, Size>& v)
{
return get<Type, Size, 2, my_vector<Type, Size>>::apply(v);
}
template<size_t I, class Type, size_t Size>
Type more(const my_vector<Type, Size>& v)
{
return get<Type, Size, I+3, my_vector<Type, Size>>::apply(v);
}
template<class T> using Vec2 = my_vector<T, 2>;
template<class T> using Vec3 = my_vector<T, 3>;
template<class T> using Vec6 = my_vector<T, 6>;
using namespace std;
auto main() -> int
{
Vec2<int> v2 { 1, 2 };
Vec3<int> v3 { 1, 2, 3 };
Vec6<int> v6 { 1, 2, 3, 4, 5, 6 };
cout << "v2: " << x(v2) << ", " << y(v2) << endl;
cout << "v3: " << x(v3) << ", " << y(v3) << ", " << z(v3) << endl;
cout << "v6: "
<< x(v6) << ", " << y(v6) << ", " << z(v6) << ", "
<< more<0>(v6) << ", " << more<1>(v6) << ", " << more<2>(v6)
<< endl;
return 0;
}
预期输出:
v2: 1, 2
v3: 1, 2, 3
v6: 1, 2, 3, 4, 5, 6
一种解决方案是让您指定 政策 来做到这一点
// base class to store members
template<size_t N>
struct Coords;
template<>
struct Coords<2> {
double x, y;
};
template<>
struct Coords<3> {
double x, y, z;
};
template<>
struct Coords<4> {
double x, y, z, w;
};
// members depend on your base class
template<class T, size_t N>
struct Vec : Coords<N>
{
using num = integral_constant<size_t, N>;
};
现在每种类型都存在以下内容(请注意 num
是一种类型,因此它不占用任何 space):
Vec<2> -> x, y and num::value = 2 (`constexpr` - compile time usable)
Vec<3> -> x, y, z and num::value = 3 //
Vec<4> -> x, y, z, w and num::value = 4 //
除非您特别想要 命名成员样式 我建议使用包含所有值的成员,例如
double _coords[N]; // N is a compile time constant so you can have arrays
因为这样的解决方案更具可扩展性、通用性并且更易于编码。
PS 我使用 double
代替 T
来简化示例。
最便携的方法是添加枚举常量:
template<class T> struct Vec2
{
enum { num_components = 2 };
};
template<class T> struct Vec3
{
enum { num_components = 3 };
};
然后在需要的地方使用V::num_components
。
如果你喜欢 C++11,那么你也可以使用 static const int num_components = 2;
而不是匿名的 enum
,但如果你需要与旧编译器兼容,那么 enum
习惯用法会让你省去一些麻烦。
给定下面的简单声明,是否可以给 class 一个常量整数特征来指定组件的数量(在本例中为 2)? Vec3 和 Vec4 分别有 3 和 4。我只想将其作为编译时常量,以各种方式实例化其他模板。它不必在运行时存在。
template<class T>
struct Vec2
{
typedef T value_type;
typedef unsigned index_type;
struct
{
T x, y;
};
};
标准库中已经有两个解决这个问题的方法。
std::array<type, size>
是一种类型的固定大小数组,它具有一个 size() 成员函数、开始和结束迭代器以及一个 [] 运算符。
std::tuple<types...>
给出可以通过索引索引的不相交类型的向量:get<i>(tuple)
或类型 get<typename>(tuple)
.
编辑:
这是一种可能的解决方案:
#include <iostream>
#include <type_traits>
#include <utility>
#include <array>
template<class Type, size_t Size>
struct my_vector
{
static constexpr size_t num_components = Size;
template<class...Args, typename = std::enable_if_t< (sizeof...(Args) == Size) > >
my_vector(Args&&...args) : _data { std::forward<Args>(args)... } {}
template<size_t I >
Type get() const {
return _data[I];
}
std::array<Type, Size> _data;
};
template<class Type, size_t Size, size_t I, class VectorType = my_vector<Type, Size>, typename = void>
struct get;
template<class Type, size_t Size, size_t I >
struct get<Type, Size, I, my_vector<Type, Size>, std::enable_if_t<I <= Size> >
{
static Type apply(const my_vector<Type, Size>& v) {
return v.get<I>();
}
};
template<class Type, size_t Size>
Type x(const my_vector<Type, Size>& v)
{
return get<Type, Size, 0, my_vector<Type, Size>>::apply(v);
}
template<class Type, size_t Size>
Type y(const my_vector<Type, Size>& v)
{
return get<Type, Size, 1, my_vector<Type, Size>>::apply(v);
}
template<class Type, size_t Size>
Type z(const my_vector<Type, Size>& v)
{
return get<Type, Size, 2, my_vector<Type, Size>>::apply(v);
}
template<size_t I, class Type, size_t Size>
Type more(const my_vector<Type, Size>& v)
{
return get<Type, Size, I+3, my_vector<Type, Size>>::apply(v);
}
template<class T> using Vec2 = my_vector<T, 2>;
template<class T> using Vec3 = my_vector<T, 3>;
template<class T> using Vec6 = my_vector<T, 6>;
using namespace std;
auto main() -> int
{
Vec2<int> v2 { 1, 2 };
Vec3<int> v3 { 1, 2, 3 };
Vec6<int> v6 { 1, 2, 3, 4, 5, 6 };
cout << "v2: " << x(v2) << ", " << y(v2) << endl;
cout << "v3: " << x(v3) << ", " << y(v3) << ", " << z(v3) << endl;
cout << "v6: "
<< x(v6) << ", " << y(v6) << ", " << z(v6) << ", "
<< more<0>(v6) << ", " << more<1>(v6) << ", " << more<2>(v6)
<< endl;
return 0;
}
预期输出:
v2: 1, 2
v3: 1, 2, 3
v6: 1, 2, 3, 4, 5, 6
一种解决方案是让您指定 政策 来做到这一点
// base class to store members
template<size_t N>
struct Coords;
template<>
struct Coords<2> {
double x, y;
};
template<>
struct Coords<3> {
double x, y, z;
};
template<>
struct Coords<4> {
double x, y, z, w;
};
// members depend on your base class
template<class T, size_t N>
struct Vec : Coords<N>
{
using num = integral_constant<size_t, N>;
};
现在每种类型都存在以下内容(请注意 num
是一种类型,因此它不占用任何 space):
Vec<2> -> x, y and num::value = 2 (`constexpr` - compile time usable)
Vec<3> -> x, y, z and num::value = 3 //
Vec<4> -> x, y, z, w and num::value = 4 //
除非您特别想要 命名成员样式 我建议使用包含所有值的成员,例如
double _coords[N]; // N is a compile time constant so you can have arrays
因为这样的解决方案更具可扩展性、通用性并且更易于编码。
PS 我使用 double
代替 T
来简化示例。
最便携的方法是添加枚举常量:
template<class T> struct Vec2
{
enum { num_components = 2 };
};
template<class T> struct Vec3
{
enum { num_components = 3 };
};
然后在需要的地方使用V::num_components
。
如果你喜欢 C++11,那么你也可以使用 static const int num_components = 2;
而不是匿名的 enum
,但如果你需要与旧编译器兼容,那么 enum
习惯用法会让你省去一些麻烦。