Home > Back-end >  Need a way to check template type and if not in the range of allowed types then have compile time er
Need a way to check template type and if not in the range of allowed types then have compile time er

Time:12-02

I need to have a template class where each object adds itself to a vector and based on the template type parameter(allowed only: string, int, float) add to the corresponding container. I need a way to have compile time checks for the type and based on the check add to the corresponding container and if the type is not one of the allowed types compile time error should be emitted. Example: code

vector<myClass<int>*> intVec;
vector<myClass<float>*> floatVec;
vector<myClass<string>*> stringVec;

template<typename T>
struct myClass
{
  myClass()
  {
     /*pseudo code
     if(T == int) {
       intVec.push_back(this);
     }
     else if(T == float) {
       floatVec.push_back(this);
     }
     else if(T == string){
       stringVec.push_back(this);
     }
     else {
       // error
     }
     */
  }
  
  T value;
 }

How can I achieve this ?

CodePudding user response:

Use specialization and a helper function, e.g.

template<typename T>
struct myClass;

inline std::vector<myClass<int>*> intVec;
inline std::vector<myClass<float>*> floatVec;
inline std::vector<myClass<std::string>*> stringVec;

template<typename T>
void add(myClass<T>*) {
    static_assert("unsupported T");
}

template<>
void add(myClass<int>* p) {
    intVec.push_back(p);
}

template<>
void add(myClass<float>* p) {
    floatVec.push_back(p);
}

template<>
void add(myClass<std::string>* p) {
    stringVec.push_back(p);
}

template<typename T>
struct myClass
{
    myClass()
    {
        add(this);
    }

    T value;
};

CodePudding user response:

In C 17 and later, you can use if constexpr and std::is_same_v, eg:

#include <type_traits>

template<typename T>
struct myClass
{
  myClass()
  {
     if constexpr (std::is_same_v<T, int>) {
       m_intVec.push_back(this);
     }
     else if constexpr (std::is_same_v<T, float>) {
       m_floatVec.push_back(this);
     }
     else if constexpr (std::is_same_v<T, std::string>){
       m_stringVec.push_back(this);
     }
     else {
       // error
     }
  }
  
  T value;
};

In earlier versions, you can use either template specialization or SFINAE instead, eg:

// via specialization

template<typename T>
struct myClass
{
};

template<>
struct myClass<int>
{
  myClass()
  {
    m_intVec.push_back(this);
  }

  int value;
};

template<>
struct myClass<float>
{
  myClass()
  {
    m_floatVec.push_back(this);
  }

  float value;
};

template<>
struct myClass<std::string>
{
  myClass()
  {
    m_stringVec.push_back(this);
  }

  std::string value;
};
// via SFINAE

#include <type_traits>

template<typename T>
struct myClass
{
  template<typename U = T, std::enable_if<std::is_same<U, int>::value, int>::type = 0>
  myClass()
  {
    m_intVec.push_back(this);
  }

  template<typename U = T, std::enable_if<std::is_same<U, float>::value, int>::type = 0>
  myClass()
  {
    m_floatVec.push_back(this);
  }

  template<typename U = T, std::enable_if<std::is_same<U, std::string>::value, int>::type = 0>
  myClass()
  {
    m_stringVec.push_back(this);
  }

  T value;
};
  • Related