6

(I'm assuming knowledge of the Abrahams/Dimov example in this question.)

Assume there is some 3rd-party code in a header that like this, which you cannot modify:

template<class T> void f(T);    // (1) base template 1
template<class T> void f(T *);  // (2) base template 2
template<> void f<>(int *);     // (3) specialization of (2)

The question is:

If I have been given the declarations above as-is, is it possible for me to now specialize the base template 1 for the case where T = int * (for example)?

Or does the mere declaration of base template 2 imply that base template 1 can no longer be specialized (at least for pointers)?

user541686
  • 205,094
  • 128
  • 528
  • 886
  • Even if you could, would that specialization be callable? Seems like base template 2 would always "win" if f is called with a pointer. – Mat Feb 09 '13 at 07:51
  • @Mat: Not from the current translation unit, as far as I can see, but it could be callable from another translation unit, I think, right? Assuming the other translation unit has a non-overloaded declaration of #1 and of the corresponding specialization. – user541686 Feb 09 '13 at 07:55
  • A TU that wouldn't have base template 2 in scope? (Not sure I understand.) Also beware of ODR violations. – Mat Feb 09 '13 at 07:56
  • @Mat: Yeah, that's what I mean. Another translation unit could declare only the first base template, along with all its specializations, but avoid defining the specialization. The specialization defined in the current TU would then be callable that way. – user541686 Feb 09 '13 at 07:57
  • if the functions are not all in the same header, you could try `#include`ing them in different namespaces – Sellorio Feb 09 '13 at 08:03

2 Answers2

2

You can overload (1) by explicitly specifying the template parameter in the angle-brackets after the function name (cf. C++11-Standard 14.7.3)

#include <iostream>
using namespace std;
template<class T> void f(T)    // (1) base template 1
{
    cout << "template<class T> void f(T)" << endl;
}

template<class T> void f(T *)  // (2) base template 2
{
    cout << "template<class T> void f(T *)" << endl;
}
//template<> void f<>(int *);     // (3) specialization of (2)

template<> void f<int*>(int *)     // (4) specialization of (1)
{
    cout << "f<int*>(int *)" << endl;
}


int main() {
    int i;
    f(&i); // calls (2) since only base-templates take part in overload resolution
    return 0;
}
tobias.loew
  • 161
  • 2
  • 8
  • Correct, although it's not an "overload". It's an explicit specialization. – Stephen305 Apr 13 '16 at 04:16
  • Could you also explicitly overload (2) by doing `template <> void f(int *) { ... }`? Is that what is inferred by the commented-out (3) line? – Sam Feb 20 '19 at 08:35
  • 1
    @SamWhitlock: In the current example: Yes. In that case the specializations `template<> void f<>(int *);` and `template <> void f(int *)` are the same. – tobias.loew Feb 21 '19 at 09:43
0

You could always try and then come to us. But I do not see why it wouldnt work. If T = int* it will work as you want. And hence no 2 would be a parameter of int* *

David G
  • 94,763
  • 41
  • 167
  • 253
Sellorio
  • 1,806
  • 1
  • 16
  • 32
  • 1
    Did I mess up the example? To me it seems like specializing for `T = int *` would require the same exact syntax as (3) (`template<> void f<>(int *);`), which therefore makes it impossible... – user541686 Feb 09 '13 at 07:47
  • @Mehrdad you are quite correct. it cant be done :) unless you find a way to force a particular overload (some other difference b/w the functions you can exploit) – Sellorio Feb 09 '13 at 07:50
  • @Mehrdad I GOT IT: you can make a class with `=` and implicit conversion `operators` that are `int` but make an overload of your function that takes the class itself in (hence it would chose that one instead of the int ones) – Sellorio Feb 09 '13 at 07:55