Partial Specialization of Function Templates

C++ function template partial specialization?

Function partial specialization is not allowed yet as per the standard. In the example, you are actually overloading & not specializing the max<T1,T2> function.

Its syntax should have looked somewhat like below, had it been allowed:

// Partial specialization is not allowed by the spec, though!
template <typename T>
inline T const& max<T,T> (T const& a, T const& b)
{ // ^^^^^ <--- supposed specializing here as an example
return a; // can be anything of type T
}

In the case of a function templates, only full specialization is allowed by the C++ standard.

There are some compiler extensions which allows partial specialization, but the code looses its portability in such case!

Why function template cannot be partially specialized?

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
}

C++ partial template function specialization

You can't partially-specialize functions, and specializations are selected after all of the template's arguments are known, so you can't do this with partial specialization.

What you can do is have a separate function template that has a single argument that simply calls through to the underlying function template:

template <typename T>
void print();

template <>
void print<float>() {
print<float, 1>();
}

template <>
void print<Eigen::half>() {
print<Eigen::half, 2>();
}

Demo

This will do what you want, but it would still be possible to override the behavior by explicitly calling print<float, 42>(). If you don't want that to be possible, you can remove the second parameter from the base function and use a type trait to determine it:

template <typename T>
struct IntDeterminer;

template <>
struct IntDeterminer<float> : std::integral_constant<int, 1>
{};

template <>
struct IntDeterminer<Eigen::half> : std::integral_constant<int, 2>
{};

template <typename T>
void print() {
std::cout << "int is " << IntDeterminer<T>::value << std::endl;
}

Demo

Partial specialization using Concepts

Function templates cannot be partially specialized (and never could be). Concepts don't change that rule.

However, function templates can be overloaded (and always could be). And concepts do make that easier:

template <typename T>
void Bar() {
std::cout << "Type T is not a hashtable" << std::endl;
}

template <Hashtable T>
void Bar() {
std::cout << "Type T is a hashtable" << std::endl;
}

int main()
{
Bar<Foo>(); // calls the first Bar
Bar<std::string>(); // calls the second Bar
}

We say the second Bar is more constrained than the first Bar.

Partial specialization of function templates

No, they can't. The draft C++0x standard has a section (14.5.5) on class template partial specialisations, but no mention of function template partial specialisations.

c++ class template partial specialization without specializing all member functions

In my experience use inheritance method (2) when you actually want a new class that inherits from the template. Use method (1) when the partial specialization is sufficiently different from the general case or general case is not defined at all and you just declare a bunch of partial specializations to make use of SFINAE.

If you simply want to enable/disable methods of a class based on template parameters then utilize SFINAE. As this way you can centralize all your definitions in one place and reason about them more easily. This is the preferred method unless you want user to make the template specializations on their own - which isn't desirable in general.

Example of SFINAE:

template <class T, size_t N>
class X {
public:
void a() {...};
X<T, N> b(X<T, N> x);
// etc
static X<T, n> c() {...};

template<size_t uN = N, std::enable_if_t<uN==3,int>=0>
void d() {...};
protected:
T data[N];
};

Here, X<int,3> x; x.d(); will compile but X<int,2> x; x.d(); will not as d() method is disabled unless N==3.

You can read a lot more about usages of SFINAE in template functions and classes in numerous online guides (note that the syntax is quite different for functions and classes).

partial template template vector specialization

Function templates can't be partial specialized; which only works with class templates and variable templates (since C++14). You can apply function template overloading instead.

e.g.

template<template<class, class> class C, class T, class A>
void handle(C<T, A> const& c)
{
cout << "General handling\n";
}

template<class T, class A>
void handle(std::vector<T, A> const& c)
{
cout << "vector handling\n";
}

A workaround for partial specialization of function template?

Anytime you ask yourself "how to simulate partial specialization for functions", you can think "overload, and let partial ordering decide what overload is more specialized".

template<int N>
using int_ = std::integral_constant<int, N>;

class Meta
{
template<int N, typename T> static constexpr T ipow(T x)
{
return ipow<N, T>(x, int_<(N < 0) ? -1 : N>());
}

template<int N, typename T> static constexpr T ipow(T x, int_<-1>)
{
// (-N) ??
return static_cast<T>(1) / ipow<-N>(x, int_<-N>());
}

template<int N, typename T> static constexpr T ipow(T x, int_<N>)
{
return x * ipow<N-1>(x, int_<N-1>());
}

template<int N, typename T> static constexpr T ipow(T x, int_<0>)
{
return 1;
}
};

I think you wanted to pass -N instead of N at the comment-marked position.



Related Topics



Leave a reply



Submit