C++ unexplained variations in template function matching with enums

349 views Asked by At

I have the following code containing a template function. When I am calling this function with second parameter being an enum: in some cases it finds the template specialization and in some cases it does not.

I had verified that enums are the same enums in both cases (e.g there are no redefinitions) and that other parameters have correct values, I found that one compilation is done with -Winline set (I did not try changing it yet) what else to look at?

class A {
public:
    template <typename T>
    int f(uint32_t id, T const& t, bool cond);

    ...
};

template <typename T>
int A::f(uint32_t id, T const& t, bool cond)
{
   ...
}

template <>
inline int A::f<int>(uint32_t, int const& t, bool cond)
{
   ....
}
2

There are 2 answers

10
templatetypedef On BEST ANSWER

For starters, typically, it's inadvisable to use template specialization as a way of overloading a template function. Template specializations interact poorly with function overloading and have some pretty arcane rules dictating when they're chosen, and in general it's considered better to just provide a regular function overload than to specialize a function template.

In this case, I'd advise changing your class to look like this:

class A {
public:
    template <typename T>
        int f(uint32_t id, T const& t, bool cond);
    int f(uint32_t id, int t, bool cond);
    ...
};

Then changing your template specialization to just be an implementation of the overload. Due to the way that C++ function overloading works, this will select the correct version of the function more accurately.

As for your particular question, the reason that your code isn't always calling the overload is that C++ makes a distinction between an enumerated type and the type int. Though there are ways of converting between ints and enumerated types, they aren't the same thing, and an overload designed to catch ints is not guaranteed to catch enumerated types as well. You are probably better off specifically overloading the function to handle the enumerated case.

0
Tony Delroy On

Not an attempted answer, but want to post more than will fit in a comment...

Basically, this shows expected behaviour (enums never matching int specialisation) for GCC 3.4.6. What compiler are you using? Can you actually provide a similar, complete program that produces the error?

#include <iostream>                                                             

struct A                                                                        
{                                                                               
  public:                                                                       
    template <typename T>                                                       
    void f(const T&) { std::cout << "general\n"; }                              
};                                                                              

template <>                                                                     
void A::f<int>(const int&) { std::cout << "specialised\n"; }                    

enum E1 { Zero, One, Two };                                                     

enum E2 { Max = INT_MAX };                                                      

int main()                                                                      
{                                                                               
    A a;                                                                        
    a.f("abc");                                                                 
    a.f(123);                                                                   
    a.f(Zero);                                                                  
    E1 e = Two;                                                                 
    a.f(e);                                                                     
    a.f(Max);                                                                   
}

Output:

general
specialised
general
general
general