How to access template specialization objects through variables

Solution for How to access template specialization objects through variables
is Given Below:

The title may not express my meaning very clearly

  1. Created a template class Map which the type is enum VertexType and specialize them
  2. exist a vector container the VertexType
  3. access different Map object through the element in vector
  4. Question: how to access different template object through a variables instead of use switch,i have try use the i as type to access the object ,obviously, it does’t work.i’m a noob in using c++ and english is poor,thank you for read this
// 1
template<VertexType> struct Map;
template<> 
struct Map<VertexType::Position2D>
{
    static constexpr DXGI_FORMAT dxgiFormat = DXGI_FORMAT_R32G32_FLOAT;
    static constexpr const char* semantic = "Position";
    static constexpr const UINT offset = 8;
};//There are other specialized versions
//VertexType is a enum class,include postion,color...```
//2
std::vector<VertexType> v;
//3
    UINT offset = 0;
    for (const auto &i : v)
    {
        switch (i)  // i is a VertexType::...
        {
        case VertexType::Position2D:
        {
            des.push_back(
                D3D11_INPUT_ELEMENT_DESC{
                    Map<VertexType::Position2D>::semantic,0,Map<VertexType::Position2D>::dxgiFormat,0,offset,
                    D3D11_INPUT_PER_VERTEX_DATA,0

                });
            offset += Map<VertexType::Position2D>::offset;
        }
        default:
            break;
        }
    }

Obvious Answer: No, template parameters are evaluated at compile-time. They cannot hold runtime values inside them (In your case, i is a runtime variable). As such, there is no straightforward way to tackle your problem.

Alternative: Well, technically, in your case, the closest you could do to achieve something like this is to wrap the tedious part inside a macro for convenience:

// ...
for (const auto &i : v)
{
    /* This macro wraps around the checking of i's value and also assigns an alias for Map that
       can be used repeatedly */
    #define ITER_VERTEX_TYPE(x, body) if (i == VertexType::x) { 
                                          using Map = Map<VertexType::x>; 
                                          body; 
                                      }

    // Now you can use it like this:
    ITER_VERTEX_TYPE(Position2D, {
        // 'Map' is a type alias defined by the macro that refers to 'Map<VertexType::Position2D>'
        des.push_back(D3D11_INPUT_ELEMENT_DESC{ Map::semantic, 0, Map::dxgiFormat, 0, offset,
                      D3D11_INPUT_PER_VERTEX_DATA, 0 });
        offset += Map::offset;
    })

    // Now do the same for the other enum values of 'VertexType' ...

    // Remove the macro since we don't need it anymore
    #undef ITER_VERTEX_TYPE
}
// ...

how to access different template object through a variables instead of use switch

So if I understand correctly, you have an enum VertexType, and a struct Map which is templated on it, and you have a variable of type VertexType, and you want to “plug in” this variable as the template argument rather than using a switch statement.

I have some bad news: this is impossible in C++.

C++ templates are not the same sort of animal as generics in C# or Java, where as you may know you can do things like that. Types of variables have to be known at compile time; you can’t do anything that would change the type of a variable at runtime.

In C++ Templates are all determined at compile time, not at run time. meaning if you have a templated struct or class, its specialization needs to be known at compile time.

If I were you I wouldn’t template anything here at all instead I would specialize and inherit. This way you can have really tidy code with much the same benefits of templates as long as you build with -O3 optimizations or Release Mode on MSVC.

Also the vector on your code above is empty so your auto for loop will do nothing. Maybe you want an std::array<Map, SIZE_HERE> instead.

Like this:

enum class VertexType
{
    POSITION2D,
    POSITION3D
};

//Not templated!
struct Map {};

struct Map_2D : public Map {
    const VertexType vt = VertexType::POSITION2D;
    //other members here
};

struct Map_3D : public Map {
    const VertexType vt = VertexType::POSITION3D;
    //Other members here
};

int main()
{
    std::vector<Map> v;

    Map_2D map2d;
    Map_3D map3d;

   v.push_back(map2d);
   v.push_back(map3d);
}