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
Should I Still Return Const Objects in C++11
C++ Virtual Function Table Memory Cost
Boost::Asio with Boost::Unique_Future
Undefined Symbols for Architecture X86_64: Which Architecture Should I Use
_Glibcxx_Use_Cxx11_Abi, Gcc 4.8 and Abi Compatibility
Detect When Network Cable Unplugged
Changing C++ Output Without Changing the Main() Function
Is It Allowed to Cast Away Const on a Const-Defined Object as Long as It Is Not Actually Modified
How to Get the Starting/Base Address of a Process in C++
C++ Logon Task Schedule Error: No Mapping Between Account Names and Security Ids Was Done
Bitwise Operations on Vector<Bool>
What Does the & (Ampersand) at the End of Member Function Signature Mean
Why Does Glgetstring(Gl_Version) Return Null/Zero Instead of the Opengl Version
Wrap Overloaded Function via Std::Function
What Exactly Is a Namespace and Why Is It Necessary
Where Ampersand "&" Can Be Put When Passing Argument by Reference