2

I have a simple templated function, defined in a library I am using

template<class T>
T create(std::vector<char>& data)
{ 
    T newValue{}; 
    /* Do something with data */
    return newValue;
}

and I want to specialize this function in case T implements a specific interface

template<class T>
std::enable_if_t<std::is_base_of<Interface, T>::value, T> create( std::vector<char>& data)
{ 
    T newValue{};
    newValue.InterfaceFunction(data);
    return newValue;
}

but I cannot make this work, the function I have specialized is not used. How can I achieve making a specialization of an already defined template function?

thorsan
  • 1,034
  • 8
  • 19
  • shouldn't it be just `template<>` in the specialization? – Oneiros Jul 03 '18 at 07:19
  • @Oneiros, I need the definition of class T in the predicate – thorsan Jul 03 '18 at 07:20
  • 1
    I think this is the reason why it is not working, you are not technically specializing the first function if you still use the T class... the compiler sees the second one as a totally different function – Oneiros Jul 03 '18 at 07:22
  • Sorry, the example was bad, I have rewritten it. Is it still not technically possible? – thorsan Jul 03 '18 at 07:24
  • Does [this thread](https://stackoverflow.com/questions/31500426/why-does-enable-if-t-in-template-arguments-complains-about-redefinitions) help? – Oneiros Jul 03 '18 at 07:24
  • @Oneiros I have tried that way, but then it becomes ambigous. – thorsan Jul 03 '18 at 07:30

1 Answers1

1

This is not template specialization but templates overloading, and function templates can't be partial specialized. The problem is that when you specify a type deriving from Interface both the function templates are exact match, which leads to ambiguity.

You can apply SFINAE.

template<class T>
std::enable_if_t<!std::is_base_of<Interface, T>::value, T> create(std::vector<char>& data)
{ 
    T newValue{}; 
    /* Do something with data */
    return newValue;
}

template<class T>
std::enable_if_t<std::is_base_of<Interface, T>::value, T> create( std::vector<char>& data)
{ 
    T newValue{};
    newValue.InterfaceFunction(data);
    return newValue;
}

LIVE

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Thank you for your answer. I know it can be done this way, IF i was allowed to change the original definition, but I am not. – thorsan Jul 03 '18 at 07:31
  • @thorsan I added some explanation about why the original definition doesn't work. – songyuanyao Jul 03 '18 at 07:37
  • @thorsan: If possible, you may still create `my_create` which calls unmodifiable `create` for non interface, else the specialized function. – Jarod42 Jul 03 '18 at 10:20
  • @Jarod42, yes, that is what I ended up doing, creating a wrapper function with SFINAE, as in the above answer, selecting the right one. – thorsan Jul 04 '18 at 06:11