Why can function templates not be partially specialized?

30.7k views Asked by At

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!
5

There are 5 answers

5
Cheers and hth. - Alf On BEST ANSWER

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
}
1
Georgy Pashkov On

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.

4
Michal W On

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.

1
Kay F. Jahnke On

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;
}
0
Jan Schultke On

Partial specializations of function templates would be extremely problematic for two reasons.

Syntactical ambiguity with function template overloading

Consider the syntax of a full specialization:

template <typename T>
void foo(T);

template <>
void foo(int); // full specialization; we could optionally write foo<int>(int)

From the template <> syntax, it is clear that this is a full specialization, not a non-template overload. However, it would not be so clear for a partial specialization:

template <typename T>
void foo(std::complex<T>);

This could either be interpreted as a second overload, or as a partial specialization foo<std::complex<T>>(std::complex<T>). This ambiguity would be extremely confusing if it existed in the language.

Even full specializations can be confusing when there are multiple overloads; see Which overload is selected when defining an explicit specialization of a function template?

Specializations don't participate in overload resolution

template <typename T>
void foo();                                   // (0) primary template

template <>
void foo(std::complex<int>);                  // (1) full specialization

template <typename T>
void foo(std::complex<T>);                    // (2) overload

If we call this with an argument of type std::complex<int>, then (2) is called, not (1), because specializations don't participate in overload resolution. This is counter-intuitive because std::complex<int> is "more specialized" than std::complex<T>.

Full specializations and hypothetical partial specializations of function templates behave contrary to intuition. Function template overloading is a much more useful feature, and should be preferred in most cases.

Workaround - Overloading, or partial specializations of class templates

In most cases, you can simply use function template overloading instead. If you need to closely imitate partial specializations, you can write function objects instead:

// primary template
template <typename T>
struct foo_object {
    void operator()(T) const { /* ... */ }
};

// partial specialization
template <typename T>
struct foo_object<std::complex<T>> {
    void operator()(std::complex<T>) const { /* ... */ }
};

// convenience function
template <typename T>
void foo(T t) {
    return foo_object<T>{}(t);
}

It may seem pointless compared to function template overloading at first, but partial specializations can delegate to each other through inheritance, which may be useful.

Such a pattern is a viable alternative to tag dispatch.

See Also

Herb Sutter's article Why Not Specialize Function Templates? explains issues regarding explicit specializations in great detail. Those equally apply to hypothetical partial specializations.