如何使用C++模板参数来确定类中的成员类型

Zeb*_*ish 11 c++ templates class

我想创建一个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;
    }

};
Run Code Online (Sandbox Code Playgroud)

我不认为语句是否在编译时没有被评估,所以这只是我想要做的一个例子.有没有办法做到这一点?或者我必须专门化每种类型,或只是重写所有不同的版本?

Jus*_*tin 21

您可能想要某种类型vec3vec2选择器类型.如果已经有模板的版本vec3vec2,只是使用它们.否则,您可以使用模板专业化:

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;
Run Code Online (Sandbox Code Playgroud)

然后你可以简单地写:

template <typename P>
struct Vertex
{
    vec3_select_t<P> position;
    vec3_select_t<P> normal;
    vec2_select_t<P> texcoords;
};
Run Code Online (Sandbox Code Playgroud)

你也可以只对Vertex模板进行专门化,但似乎有可能在vec3_select_t其他地方有用,你必须重复任何成员函数Vertex(或者让代码更复杂)


Joh*_*itb 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;
};
Run Code Online (Sandbox Code Playgroud)

通过对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{};
Run Code Online (Sandbox Code Playgroud)

现在它不再需要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;
};
Run Code Online (Sandbox Code Playgroud)

丑陋的decltype写作可以通过使用autoaswell 来解决

template<auto &t>
using type_of = typename std::remove_reference_t<decltype(t)>::type;
Run Code Online (Sandbox Code Playgroud)

所以你可以写

type_of<D3> position;
type_of<D3> normal;
type_of<D2> texcoords;
Run Code Online (Sandbox Code Playgroud)