Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template specialization and enable_if problems [duplicate]

Tags:

I am running into a problem regarding the appropriate usage of enable_if and template specialization.

After modifying the example (for confidentiality reasons), here's a comparable example:

I have function called "less" that checks if 1st arg is less than 2nd arg. Let's say I want to have 2 different kinds of implementations depending on the type of input - 1 implementation for integer and another for double.

The code that I have so far looks like this -

#include <type_traits> #include <iostream>  template <class T,           class = typename std::enable_if<std::is_floating_point<T>::value>::type>      bool less(T a, T b) {   // .... }  template <class T,           class = typename std::enable_if<std::is_integral<T>::value>::type>      bool less(T a, T b) {   // .... }  int main() {     float a;     float b;     less(a,b);     return 0; } 

The above code does not compile because - It says that I am re-defining the less method.

Errors are:

Z.cpp:15:19: error: template parameter redefines default argument           class = typename std::enable_if<std::is_integral<T>::value>::type>                    ^ Z.cpp:9:19: note: previous default template argument defined here           class = typename std::enable_if<std::is_floating_point<T>::value>::type>                   ^  Z.cpp:16:11: error: redefinition of 'less'      bool less(T a, T b) {           ^  Z.cpp:10:11: note: previous definition is here      bool less(T a, T b) {           ^  Z.cpp:23:5: error: no matching function for call to 'less'     less(a,b);     ^~~~  Z.cpp:15:43: note: candidate template ignored: disabled by 'enable_if'       [with T = float]           class = typename std::enable_if<std::is_integral<T>::value>::type>                                           ^ 3 errors generated. 

Can someone point out what's the mistake here?

like image 604
user855 Avatar asked Apr 07 '15 21:04

user855


1 Answers

Default template arguments are not part of the signature of a function template. So in your example you have two identical overloads of less, which is illegal. clang complains about the redefinition of the default argument (which is also illegal according to §14.1/12 [temp.param]), while gcc produces the following error message:

error: redefinition of 'template<class T, class> bool less(T, T)'

To fix the error move the enable_if expression from default argument to a dummy template parameter

template <class T,           typename std::enable_if<std::is_floating_point<T>::value, int>::type* = nullptr>      bool less(T a, T b) {   // .... }  template <class T,           typename std::enable_if<std::is_integral<T>::value, int>::type* = nullptr>      bool less(T a, T b) {   // .... } 

Another option is to use enable_if in the return type, though I feel this is harder to read.

template <class T>       typename std::enable_if<std::is_floating_point<T>::value, bool>::type        less(T a, T b) {   // .... }  template <class T>      typename std::enable_if<std::is_integral<T>::value, bool>::type       less(T a, T b) {   // .... } 
like image 84
Praetorian Avatar answered Sep 21 '22 05:09

Praetorian