0
votes

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

2

2 Answers

4
votes

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
    }
};
1
votes

Barry's answer is perfect.

Here is some explanation and suggestions:

http://en.cppreference.com/w/cpp/types/enable_if

"A common mistake is to declare two function templates that differ only in their default template arguments. This is illegal because default template arguments are not part of function template's signature, and declaring two different function templates with the same signature is illegal."