17

can someone explain why the compiler accepts only this code

template<typename L, size_t offset, typename enable_if< (offset<sizeof(L)), int >::type =0>
void a_function(){}

template<typename L, size_t offset, typename enable_if< (offset==sizeof(L)), int >::type =0>
void a_function(){}

but not this:

template<typename L, size_t offset, typename enable_if< (offset<sizeof(L)), int >::type =0>
class a_class{};

template<typename L, size_t offset, typename enable_if< (offset==sizeof(L)), int >::type =0>
class a_class{};

The compiler sees the second class template as a redefinition of the first.

Lorenzo Pistone
  • 5,028
  • 3
  • 34
  • 65

2 Answers2

15

You have to use specialization for classes. Typically, it is done with an extra parameter:

template <class P, class dummy = void>
class T;

template <class P>
class T<P, typename enable_if<something, void>::type> {
   the real thing
};

Two class (or class template) declarations with the same name should always declare the same class or class template (or be a specialization, in which case it is still the same template).

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
jpalecek
  • 47,058
  • 7
  • 102
  • 144
  • `typename enable_if::type = 0` is equivalent to `int __anonymous_param = 0` when `something` is true. – kennytm Jan 31 '12 at 12:55
  • But why did it succeed for the functions? – Lightness Races in Orbit Jan 31 '12 at 12:55
  • 2
    @LightnessRacesinOrbit because you can overload functions, but not types. In the function version you are defining two potential overloads (for different sets of types) while int the second case you are defining two templates with the same name which cannot be done. Two functions with one name fine (as long as they are not ambiguous), two types with the same name, not so fine, even if they are actually type templates. – David Rodríguez - dribeas Jan 31 '12 at 12:59
  • @LightnessRacesinOrbit Because functions can be overloaded. And templated functions are overloaded according to SFINAE. – lapk Jan 31 '12 at 13:00
  • @LightnessRacesinOrbit: I'd say it's because two function definitions with the same name are still two function definitions, but two class (class template) definitions are always the same class/template. – jpalecek Jan 31 '12 at 13:04
  • But where's the overload? Both instantiations have the same signature. Or does that in fact not matter? (the two function definitions however do _not_ have the same name, which would be an error) – Lightness Races in Orbit Jan 31 '12 at 13:05
  • "Both instantiations have the same signature" they don't, one has `offset – Lorenzo Pistone Jan 31 '12 at 13:38
  • @Lorenzo: No, that's not part of the function's signature. That's part of the template argument list. Both instantiations have the signature `void()`. – Lightness Races in Orbit Jan 31 '12 at 14:10
  • I believe that when it comes to function template, the compiler takes into account the template arguments list. See http://stackoverflow.com/questions/8743159/boostenable-if-not-in-function-signature – Lorenzo Pistone Jan 31 '12 at 14:32
1

You probably want to do something like this (ideone.com link):

#include <iostream>

template< typename PL, size_t pOffset, int pC = int( sizeof(PL) ) - int( pOffset ) >= 0 ? ( int( sizeof(PL) ) - int( pOffset ) == 0 ? 0 : 1 ) : -1 >
class TClass
{
};

template< typename PL, size_t pOffset >
class TClass< PL, pOffset, -1 >
{
 public:
  static int const sI = -1;
};

template< typename PL, size_t pOffset >
class TClass< PL, pOffset, 0 >
{
 public:
  static int const sI = 0;
};

template< typename PL, size_t pOffset >
class TClass< PL, pOffset, 1 >
{
 public:
  static int const sI = 1;
};

int main(void )
{
 TClass< char, 0 > lC0;
 TClass< char, 1 > lC1;
 TClass< char, 2 > lC2;

 std::cout << lC0.sI << " : " << lC1.sI << " : " << lC2.sI << std::endl;

 return ( 0 );
}

Program output:

1 : 0 : -1
lapk
  • 3,838
  • 1
  • 23
  • 28