user1765354 user1765354 - 3 years ago 69
C++ Question

How do I cast a C++ template parameter?

I have a C++ function that looks like this:

template <class T> void MyClass::set(T value) {
if (std::is_same<T, std::string>::value) {
stringValue_ = value;
} else if (std::is_same<T, int>::value) {
intValue_ = value;
}
}


However, I'm getting compiler errors. Apparently it believes that the type of T is always a std::string:

assigning to 'int' from incompatible type 'std::__cxx11::basic_string<char>'


Additionally, when I try to cast the value to an int like (int)value, I get casting errors. The entire point of this function is to take in a template parameter value and then assign it to the correct variable of the class based on the parameter's actual type. Please let me know which misconceptions or errors I'm making here.

Answer Source

You cannot cast a template parameter, in the manner you're trying to do:

template <class T> void MyClass::set(T value) {
  if (std::is_same<T, std::string>::value) {
    stringValue_ = value;
  } else if (std::is_same<T, int>::value) {
    intValue_ = value;
  }
}

The key concept here is that a template function gets expanded in its entirety when it gets instantiated.

If say, for a given template instance, the T template parameter is an integer. This template then get instantiated in approximately the following manner:

void MyClass::set(int value)
{
     if (false)
     {
         stringValue_=value;
     }

Your attempt here to set stringValue, that's presumably a std::string, to an int, is not going to be very successful. Just because the if condition is false, does not make this chunk of code go away. It still must be valid C++, even if it never gets executed, and this is not valid C++. This is the explanation for your compilation error.

Some features in the newest C++17 standard will make these kinds of constructs actually possible. However, pre-C++17 the general approach to solving this kind of a problem is to use template specialization:

template<typename T> void MyClass::set(T value);

template<> void MyClass::set<int>(int value)
{
    intValue_=value;
}

template<> void MyClass::set<std::string>(std::string value)
{
    stringValue_=value;
}

Or, forget templates entirely, and just define two separate set() methods.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download