user819640 user819640 - 2 months ago 16
C++ Question

Template Specialization of class method. "Function template already defined"

I've seen lots of SO questions about specialization in the context of methods, but not functions belonging to classes. I'm having a hard time translating the knowledge passed on from those questions to my problem here.

I'm mucking around with a class I created in the past to learn and I would like to have a specialization for arithmetic types.

template <typename T>
class Vector3
{
public:
T x;
T y;
T z;

public:
operator std::string() const;
}


This is the specialization I am trying to do:

template<typename T = std::enable_if<std::is_arithmetic<T>::value, T>::type>
inline Vector3<T>::operator std::string() const {

std::stringstream ss;
ss << "NOT NUMBER {" << x << ", " << y << ", " << z << "}";

return ss.str();
}

template<typename T = std::enable_if<!std::is_arithmetic<T>::value, T>::type>
inline Vector3<T>::operator std::string() const {

std::stringstream ss;
ss << "NUMBER {" << x << ", " << y << ", " << z << "}";

return ss.str();
}


However when I try to compile, I get


error C2995: 'Vector3::operator std::string(void) const': function
template has already been defined


When I google this, it is usually cases where people have defined their class/method in the CPP file as well as the header file. As I only do this in the header file, I can only assume the enable_if is not correct. When I look at other examples, they just do specialization on , , but I'd like to use the is_arithmitic way.

What am I doing wrong? Thanks in advance

Answer

The default here:

template<typename T = XXX>
inline Vector3<T>::operator std::string() const { ... }

doesn't matter at all, there's no deduction going on at this point, and T is already defined. It's legal, but it's just noise.

Now, you can't partially specialize a member function in a class template either, but we can dispatch on traits:

template <class T>
class Vector3 {
public:
    // ...
    operator std::string() const {
        return as_string(std::is_arithmetic<T>{});
    }

private:
    std::string as_string(std::true_type ) {
        // implementation for arithmetic types
    }

    std::string as_string(std::false_type ) {
        // implementation for non-arithmetic types
    }
};