简体   繁体   中英

How to specialize a non-templated-member function of a template class for multiple types?

I'm biting of my nails on the syntax required to partially specialize a member function for multiple types. Here is what I have:

#include <cstdint>
#include <string>

class Property
{
public:
    virtual int read(uint8_t *) = 0;
};

template<typename T>
class PropertyValue
{
    T value_;
public:
    int read(uint8_t *);
};

// specialized for std::string
template<>
int PropertyValue<std::string>::read(uint8_t *buf) { /* put string-value to buf */}

Now I would want to specialize the read-function for different enum-types. I tried a combination of enable_if and is_same which looks promissing, then putting it inside the template-declaration (compiler told me there are now 2 template arguments whereas 1 was expected).

Putting it inside the class-definition was not working either. Outside ... well, here's what I currently have.

// specialize for some enums
template<typename T>
typename std::enable_if<std::is_same<T, enum Enum1>::value ||
                        std::is_same<T, enum Enum2>::value, int>::type
PropertyValue<T>::read(uint8_t *buf)
{
    return encode_enum(buf, value_);
}

Where is my thinking wrong?

EDIT: Writing it like this compiles and works:

template<>
int PropertyValue<Enum 1>::read(uint8_t *buf)
{
    return encode_enum(buf, value_);
}

template<>
int PropertyValue<Enum 2>::read(uint8_t *buf)
{
    return encode_enum(buf, value_);
}

PropertyValue::value itself is not a template. It's not a template class, it's not a template function. It's a member of a template class, which is not the same thing as being a template itself.

You have to specialize the entire class.

template<>
class PropertyValue<std::string>
{
    std::string value_;
public:
    int read(uint8_t *)
    {
          // Your specialization goes here.
    }
};

Even if read() itself was a template, you must still specialize its class, before you can specialize a template class's template member.

Of course, if your template class has many other members and methods, every one of them have to be specialized here, leading to plenty of code getting duplicated. At that point, you will be faced with several options for refactoring out that duplicated code. The best approach for that depends on the particular details.

But that's how it's done...

EDIT: one common approach is to use a helper template class:

template<typename T> class PropertyValue; // Forward declaration

template<typename T> class do_read {
public:

    static int do_it( PropertyValue<T> &me, uint8_t *p )
    {
        // your default implementation
    }
};

template<> class do_read<std::string> {
public:

    static int do_it( PropertyValue<std::string> &me, uint8_t *p )
    {
        // your specialization
    }
};


template<typename T>
class PropertyValue
{
    T value_;
public:
    int read(uint8_t *p)
    {
          return do_read<T>::do_it(*this, p);
    }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM