C++ function template partial specialization?
Function partial specialization is not yet allowed 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
return 10;
}
In the case of a function templates, only full specialization is allowed by the C++ standard, -- excluding the compiler extensions!
Parameterization and function template partial specialization is not allowed
Another way is to turn the templated constant into a constant argument which the compiler can optimise away.
step 1: define the concept of a rotate_distance:
template<unsigned int R> using rotate_distance = std::integral_constant<unsigned int, R>;
step 2: define the rotate functions in terms of overloads of a function which takes an argument of this type:
template<unsigned int R>
uint32_t LeftRotate(uint32_t v, rotate_distance<R>)
Now, if we wish we can simply call LeftRotate(x, rotate_distance<y>())
, which seems to express intent nicely,
or we can now redefine the 2-argument template form in terms of this form:
template<unsigned int Dist, class T>
T LeftRotate(T t)
{
return LeftRotate(t, rotate_distance<Dist>());
}
Full Demo:
#include <iostream>
#include <stdint.h>
#include <utility>
template<unsigned int R> using rotate_distance = std::integral_constant<unsigned int, R>;
template<typename T, unsigned int R>
inline T LeftRotate(unsigned int v, rotate_distance<R>)
{
static const unsigned int THIS_SIZE = sizeof(T)*8;
static const unsigned int MASK = THIS_SIZE-1;
return T((v<<R)|(v>>(-R&MASK)));
}
template<unsigned int R>
uint32_t LeftRotate(uint32_t v, rotate_distance<R>)
{
__asm__ ("roll %1, %0" : "+mq" (v) : "I" ((unsigned char)R));
return v;
}
#if __x86_64__
template<unsigned int R>
uint64_t LeftRotate(uint64_t v, rotate_distance<R>)
{
__asm__ ("rolq %1, %0" : "+mq" (v) : "J" ((unsigned char)R));
return v;
}
#endif
template<unsigned int Dist, class T>
T LeftRotate(T t)
{
return LeftRotate(t, rotate_distance<Dist>());
}
int main(int argc, char* argv[])
{
std::cout << "Rotated: " << LeftRotate((uint32_t)argc, rotate_distance<2>()) << std::endl;
std::cout << "Rotated: " << LeftRotate((uint64_t)argc, rotate_distance<2>()) << std::endl;
std::cout << "Rotated: " << LeftRotate<2>((uint64_t)argc) << std::endl;
return 0;
}
pre-c++11 compilers
Prior to c++11 we didn't have std::integral_constant, so we have to make our own version.
For our purposes, this is sufficient:
template<unsigned int R> struct rotate_distance {};
full proof - note the effect of optimisations:
https://godbolt.org/g/p4tsQ5
Function template overloading - partial specialization
The first class above compiles and returns back the appropriate
Foo
Yes, because
template<>
foo1& Foo::getFoo( Param a, Param b, Param c ) {
return getFoo1( a, b, c );
}
it's a full specialization of the template method getFoo()
template<class FooType>
static FooType& getFoo( Param a, Param b, Param c );
with the FooType
type fixed to foo1
.
And you can make a full specialization of a template function (or method).
However, in the second class
Bar
I keep getting compiler errors that function definition is not matching an existing declaration.
Sure.
Because you're trying to partial specialize the template method getBar()
template<typename Type, template<typename> class BarType, class... FuncParams>
static BarType<Type>& getBar( FuncParams... params );
fixing BarType
to bar1
template<typename Type, class... FuncParams>
bar1<Type>& Bar::getBar( FuncParams... params ) {
return {};//getBar1( params... );
}
But you can't partial specialize a template function/method. It's forbidden by the language.
If you want something similar, you have to pass through the partial specialization of a struct (or class).
--- EDIT ---
The OP ask
You said, "you have to pass through the partial specialization of a struct( or class)." Okay; so there is a work around: would you be able to provide a small basic example?
There are many ways to use partial specialization of structs (classes) to bypass the non-partial-specialization limits for functions/methods.
In the following basic example I propose a template foo
struct with a template func()
method. The single template parameter for foo
is the type returned by func()
; the variadic template type list for func()
is the list of types of arguments.
But you can play this game in differents modes.
#include <iostream>
template <typename>
struct bar1
{ template <typename ... Args> bar1 (Args && ...) { } };
template <typename>
struct bar2
{ template <typename ... Args> bar2 (Args && ...) { } };
template <typename>
struct foo;
template <typename T>
struct foo<bar1<T>>
{
template <typename ... Args>
static bar1<T> func (Args && ... as)
{ return { std::forward<Args>(as)... }; }
};
template <typename T>
struct foo<bar2<T>>
{
template <typename ... Args>
static bar2<T> func (Args && ... as)
{ return { std::forward<Args>(as)... }; }
};
int main()
{
foo<bar1<int>>::func(1, "two", 3.0);
foo<bar2<long>>::func(4.0f, "five", 6L);
}
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
}
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.
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 Specialization of a variadic template function
You can do something like this:
template <class C, typename ...Arguments>
auto addStyleClassRecursiveImpl(int, C *c, Arguments... arg)
-> decltype(c->addStyleClass(arg...), void()) {
c->addStyleClass(arg...);
// ... C has addStyleClass
}
template <class C, typename ...Arguments>
void addStyleClassRecursiveImpl(char, C *c, Arguments... arg) {
// ... C has not addStyleClass
}
template <typename... T>
void addStyleClassRecursive(T ...&&t) {
addStyleClassRecursiveImpl(0, std::forward<T>(t)...);
// ...
}
The idea is to tag-dispatch the request to an internal implementation (called addStyleClassRecursiveImpl
in the example) and use sfinae and function overloading to pick the right version up.
And of course, you cannot partially specialize a function template.
Function template partial specialization - are there any workaround?
Your syntax is all wrong. Make it
template <typename T, NodeCachingOptions opt>
T* CreateSObject(const MPath& ob)
{
CreateSObject_Impl<T, opt> temp;
return temp.call(ob);
}
You pass the value of type NodeCachingOptions
as the second template paramter of CreateSObject_Impl
, not the type itself.
You may want to make call
a static member of CreateSObject_Impl
, and write return CreateSObject_Impl<T, opt>::call(ob);
Related Topics
How to Output Coloured Text to a Linux Terminal
What's the Difference Between _Pretty_Function_, _Function_, _Func_
Using Opencv and Svm With Images
How Does #Include ≪Bits/Stdc++.H≫ Work in C++
Does It Make Any Sense to Use Inline Keyword With Templates
Why Can't I Use Float Value as a Template Parameter
How Can a Windows Service Execute a Gui Application
Variable Initialization in C++
Std::Endl Is of Unknown Type When Overloading Operator≪≪
Getting Size of Array from Pointer C++
What Open Source C++ Static Analysis Tools Are Available