90

I know the language specification forbids partial specialization of function template.

I would like to know the rationale why it forbids it? Are they not useful?

template<typename T, typename U> void f() {}   //allowed!
template<> void f<int, char>()            {}   //allowed!
template<typename T> void f<char, T>()    {}   //not allowed!
template<typename T> void f<T, int>()     {}   //not allowed!
Lightness Races in Orbit
  • 358,771
  • 68
  • 593
  • 989
Nawaz
  • 327,095
  • 105
  • 629
  • 812
  • For `template void f(T t, U u) {}` also `template<> void f(int t, char u) {}` is allowed. – dashesy Jul 22 '16 at 21:46
  • 11
    I find it interesting that people keep providing workarounds when the question is not "how can I achieve a similar goal" but "what's the rationale behind this behavior"... I myself do not know the reason of this choice, but I assume the committee must have had a reason to forbid function template partial specialization. So far the "closest" explanation is the link posted by Georgy, which only points out the potential "risks" of function template partial specialization when overloads are present. However, I don't think that's a reason to forbid this feature, so I assume there is more to this.. – bartgol Oct 03 '17 at 19:58

4 Answers4

59

AFAIK that's changed in C++0x.

I guess it was just an oversight (considering that you can always get the partial specialization effect with more verbose code, by placing the function as a static member of a class).

You might look up the relevant DR (Defect Report), if there is one.

EDIT: checking this, I find that others have also believed that, but no-one is able to find any such support in the draft standard. This SO thread seems to indicate that partial specialization of function templates is not supported in C++0x.

EDIT 2: just an example of what I meant by "placing the function as a static member of a class":

#include <iostream>
using namespace std;

// template<typename T, typename U> void f() {}   //allowed!
// template<> void f<int, char>()            {}   //allowed!
// template<typename T> void f<char, T>()    {}   //not allowed!
// template<typename T> void f<T, int>()     {}   //not allowed!

void say( char const s[] ) { std::cout << s << std::endl; }

namespace detail {
    template< class T, class U >
    struct F {
        static void impl() { say( "1. primary template" ); }
    };

    template<>
    struct F<int, char> {
        static void impl() { say( "2. <int, char> explicit specialization" ); }
    };

    template< class T >
    struct F< char, T > {
        static void impl() { say( "3. <char, T> partial specialization" ); }
    };

    template< class T >
    struct F< T, int > {
        static void impl() { say( "4. <T, int> partial specialization" ); }
    };
}  // namespace detail

template< class T, class U >
void f() { detail::F<T, U>::impl(); }    

int main() {
    f<char const*, double>();       // 1
    f<int, char>();                 // 2
    f<char, double>();              // 3
    f<double, int>();               // 4
}
Community
  • 1
  • 1
Cheers and hth. - Alf
  • 135,616
  • 15
  • 192
  • 304
  • do you have the standard in n3225 ? I did a quick search but could not find it :/ – Matthieu M. Feb 24 '11 at 08:14
  • 1
    ah sorry... a word was missing. I have the document, but could not find the particular *paragraph*. Though given your edit, I guess it's simply because it's not in there :) – Matthieu M. Feb 24 '11 at 09:25
  • 3
    This is not changed in C++0x. I also doubt its utility. You can always overload the template and make use of partial *ordering*. – Johannes Schaub - litb Feb 24 '11 at 09:35
  • 1
    Late update: did not change even in C++17 eight years later, and doesn't seem to enter C++20 either. Cannot see any reason for, though... – Aconcagua Jun 29 '19 at 12:29
  • This is by far the most comprehensive implementation of the concept, I believe – Victor Nov 24 '19 at 08:46
19

Well, you really can't do partial function/method specialization however you can do overloading.

template <typename T, typename U>
T fun(U pObj){...}

// acts like partial specialization <T, int> AFAIK 
// (based on Modern C++ Design by Alexandrescu)
template <typename T>
T fun(int pObj){...} 

It is the way but I do not know if it satisfy you.

Michal W
  • 773
  • 7
  • 24
  • 2
    Wow my mind was filled with templates such that I really forgot how simple things could be :) – Johannes Feb 01 '17 at 14:28
  • 2
    Unfortunately it's not the case when you want to pass variadic arguments after partially specializing the function.. :( – Gwangmu Lee May 09 '19 at 01:59
  • Im not sure what was meant by passing variadic templates, so I'd like to know how it is different from a partial specialization. Could you please provide more details? – beginpluses Jun 27 '19 at 17:45
  • What if you want just two functions for all integral and float types? – Dmitriy Dokshin Jun 02 '20 at 20:10
15

In general, it's not recommended to specialize function templates at all, because of troubles with overloading. Here's a good article from the C/C++ Users Journal: http://www.gotw.ca/publications/mill17.htm

And it contains an honest answer to your question:

For one thing, you can't partially specialize them -- pretty much just because the language says you can't.

Georgy Pashkov
  • 1,266
  • 7
  • 11
11

Since you can partially specialize classes, you can use a functor:

#include <iostream>

template < typename dtype , int k > struct fun
{
 int operator()()
 {
  return k ;
 }
} ;

template < typename dtype > struct fun < dtype , 0 >
{
 int operator()()
 {
  return 42 ;
 }
} ;

int main ( int argc , char * argv[] )
{
 std::cout << fun<float,5>()() << std::endl ;
 std::cout << fun<float,0>()() << std::endl ;
}
Kay F. Jahnke
  • 351
  • 2
  • 7
  • 1
    You can then use a single function template to make the calls, getting rid of the ugly `()()` syntax. – tmr232 Dec 04 '16 at 15:47