如何使用C++模板参数来确定类中的成员类型
How can I use C++ template argument to decide which type of member is in a class
我想创建一个顶点类,并希望通过能够创建 32 位浮点数和 64 位双精度版本(也许是 int 版本)来泛型它。我想这样做:
template <typename P>
struct Vertex
{
if (typeid(P) == typeid(float))
{
vec3 position;
vec3 normal;
vec2 texcoords;
}
else if (typeid(P) == typeid(double))
{
dvec3 position; // This is a double vector
dvec3 normal;
dvec2 texcoords;
}
else if (typeid(P) == typeid(int))
{
ivec3 position; // This is an integer vector
ivec3 normal;
ivec2 texcoords;
}
};
我不认为语句在编译时没有被计算,所以这只是我想做什么的一个说明。有什么办法可以做到这一点吗?还是我必须专门化每种类型,或者只是重写所有不同的版本?
您可能希望拥有某种vec3
和vec2
选择器类型。如果已经有 vec3
和 vec2
的模板化版本,只需使用它们。否则,您可以使用模板专用化:
template <typename T>
struct vec_selector {};
template <>
struct vec_selector<float> {
using vec3_type = vec3;
using vec2_type = vec2;
};
template <>
struct vec_selector<double> {
using vec3_type = dvec3;
using vec2_type = dvec2;
};
template <>
struct vec_selector<int> {
using vec3_type = ivec3;
using vec2_type = ivec2;
};
template <typename P>
using vec3_select_t = typename vec_selector<P>::vec3_type;
template <typename P>
using vec2_select_t = typename vec_selector<P>::vec2_type;
然后你可以简单地写:
template <typename P>
struct Vertex
{
vec3_select_t<P> position;
vec3_select_t<P> normal;
vec2_select_t<P> texcoords;
};
您也可以只专门化Vertex
模板,但似乎在其他地方vec3_select_t
很有用,并且您必须在Vertex
上重复任何成员函数(否则会使代码更复杂)
这是一个替代方案
template<typename T>
struct Type { typedef T type; };
template<typename T>
inline constexpr Type<T> type{};
template <typename P>
struct Vertex
{
static constexpr auto D3 = []{
if constexpr(std::is_same_v<P,float>)
return type<vec3>;
else if constexpr(std::is_same_v<P,double>)
return type<dvec3>;
else if constexpr(std::is_same_v<P,int>)
return type<ivec3>;
}();
static constexpr auto D2 = []{
if constexpr(std::is_same_v<P,float>)
return type<vec2>;
else if constexpr(std::is_same_v<P,double>)
return type<dvec2>;
else if constexpr(std::is_same_v<P,int>)
return type<ivec2>;
}();
typename decltype(D3)::type position;
typename decltype(D3)::type normal;
typename decltype(D2)::type texcoords;
};
在Type
模板上多做一点努力,你可以对lambda的代码进行相当多的改进(也许你已经看到了boost hana,它也遵循了这个想法)
template<typename T>
struct Type {
typedef T type;
friend constexpr bool operator==(Type, Type) {
return true;
}
};
template<typename T1, typename T2>
constexpr bool operator==(Type<T1>, Type<T2>) {
return false;
}
template<typename T>
inline constexpr Type<T> type{};
现在不再需要std::is_same_v
template <typename P>
struct Vertex
{
static constexpr auto D3 = [](auto t) {
if constexpr(t == type<float>)
return type<vec3>;
else if constexpr(t == type<double>)
return type<dvec3>;
else if constexpr(t == type<int>)
return type<ivec3>;
}(type<P>);
static constexpr auto D2 = [](auto t) {
if constexpr(t == type<float>)
return type<vec2>;
else if constexpr(t == type<double>)
return type<dvec2>;
else if constexpr(t == type<int>)
return type<ivec2>;
}(type<P>);
typename decltype(D3)::type position;
typename decltype(D3)::type normal;
typename decltype(D2)::type texcoords;
};
丑陋的decltype
书写也可以通过使用auto
来修复
template<auto &t>
using type_of = typename std::remove_reference_t<decltype(t)>::type;
所以你可以写
type_of<D3> position;
type_of<D3> normal;
type_of<D2> texcoords;
OP在评论中提到他们正在使用GML。
GLM 向量实际上是模板,因此不需要复杂的解决方案:
template <typename P>
struct Vertex
{
tvec3<P> position;
tvec3<P> normal;
tvec2<P> texcoords;
};
这只是贾斯汀解决方案的补充。反正其实是他的。使用std::condition的想法是François Andrieux在评论中给出的想法。大致如下:
template <typename P>
struct vertex
{
using vec3_t = std::conditional_t <std::is_same_v<float, P>,
/*IF FLOAT*/ vec3,
/*OTHERWISE*/ std::conditional_t <is_same_v<double, P>,
/*IF DOUBLE*/ dvec3,
/*IF INT*/ ivec3>>;
vec3_t position;
vec3_t normal;
//vec2_t texcoords; WILL HAVE TO TYPEDEF THIS AS WELL.
};
Johannes Schaub 在基于 constexpr 和 decltype 的评论中给出了两种不同的解决方案。
相关文章:
- 根据模板类型选择类模板的成员类型?
- 函数模板签名中忽略的成员类型def 的访问说明符
- 在C++如何从数组中提取成员并返回成员类型的数组?
- C++从成员类型中扣除类型的功能模板?
- 无法初始化以 std::byte 作为成员类型的位字段
- 构造函数可以更改默认成员类型吗?
- 使用相同方法但不同成员类型构建类的最佳方法
- 允许通过指向方法的成员参数的指针来推断模板参数所指向的成员类型
- 使用 std::条件根据模板参数选择成员类型
- CRTP:如何推断要用作返回类型的成员类型?
- 对成员类型的成员方法使用 std::result_of<>
- C :可以从类及其受保护的成员类型继承可以继承吗?
- 如何在不指定不必要的模板参数的情况下使用模板类的成员类型
- 基类数据成员类型取决于派生类
- C 多态性:允许模棱两可的成员类型
- 使用使用成员类型别名的构造函数来推论类模板参数
- 获取与在模板参数中传递的函数成员类型相同的类
- 如果静态成员未初始化并且成员类型是类本身,该怎么办?
- boost::bind 无法绑定到纯虚拟基类中定义的非静态函数模板成员类型
- 将联合强制转换为其成员类型之一