我想创建一个Vertex类,并希望通过能够创建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;
}
};
我不认为语句是否在编译时没有得到评估,所以这只是我想要做的事情的一个例子。有没有办法做到这一点?或者我必须专门化每种类型,或只是重写所有不同的版本?
答案 0 :(得分:21)
您可能希望拥有某种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
,并且您必须重复{{1}上的任何成员函数(或者让代码更复杂)
答案 1 :(得分:5)
这是另一种选择
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的代码(也许你已经看过了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;
答案 2 :(得分:2)
GLM向量实际上是模板,因此不需要复杂的解决方案:
template <typename P>
struct Vertex
{
tvec3<P> position;
tvec3<P> normal;
tvec2<P> texcoords;
};
答案 3 :(得分:0)
这只是贾斯汀解决方案的补充。无论如何,这实际上是他的。使用std :: conditional的想法是FrançoisAndrieux在评论中给出的想法。这些方面的东西:
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。