Search code examples
c++templatestypenameredefinitionenable-if

enable_if in template Parameters Creates Template Redefinition Error


In this answer what I really wanted to do is define a typename in my template parameters which could be used in the cast and return.

So this:

template <typename T>
auto caster(T value)
  -> typename std::enable_if<sizeof(unsigned char) == sizeof(T), unsigned char>::type
{ return reinterpret_cast<unsigned char&>(value); }

Would become this:

template <typename T, typename R = std::enable_if<sizeof(unsigned char) == sizeof(T), unsigned char>::type >
R caster(T value) { return reinterpret_cast<R&>(value); }

This works and behaves as desired for a single template specialization, but say that I add another overload:

template <typename T, typename R = std::enable_if<sizeof(short) == sizeof(T), short>::type>
R caster(T value) { return reinterpret_cast<R&>(value); }

Now I get an error:

error C2995: 'R caster(T)' : function template has already been defined

Is there a way to convince the compiler that only one of these specializations will actually build for any given call?


Solution

  • It seems that the best solution here may be to use a slew of conditionals, which would prevent me from having to fool with template specializations:

    template <typename T, typename R = std::conditional<sizeof(T) == sizeof(unsigned char),
                                                        unsigned char,
                                                        conditional<sizeof(T) == sizeof(unsigned short),
                                                                    unsigned short,
                                                                    conditional<sizeof(T) == sizeof(unsigned long),
                                                                                unsigned long,
                                                                                enable_if<sizeof(T) == sizeof(unsigned long long), unsigned long long>::type>::type>::type>::type>
    R caster(T value){ return reinterpret_cast<R&>(value); }
    

    My apologies to the reader cause it's like reading nested ternaries. However I'm currently unaware of a cleaner way to handle this.

    This sadly still doesn't prevent the user from stomping on all my defaulting by providing his own second template parameter as mentioned by hvd.

    EDIT:

    I've asked another question here which has a solution that doesn't require placing the typename in the template definition and doesn't require declaring the type twice.