Do template specializations require template<> syntax? - c++

I have a visitor class resembling this:
struct Visitor
{
template <typename T>
void operator()(T t)
{
...
}
void operator()(bool b)
{
...
}
};
Clearly, operator()(bool b) is intended to be a specialization of the preceding template function.
However, it doesn't have the template<> syntax that I'm used to seeing before it, declaring this as a template specialization. But it does compile.
Is this safe? Is this correct?

Your code is not a template specialization, but rather a non-templated function. There are some differences there. The non-templated operator() will take precedence over a templated version (for an exact match, but type conversions will not take place there) but you can still force the templated function to be called:
class Visitor
{
public: // corrected as pointed by stefanB, thanks
template <typename T>
void operator()( T data ) {
std::cout << "generic template" << std::endl;
}
void operator()( bool data ) {
std::cout << "regular member function" << std::endl;
}
};
template <> // Corrected: specialization is a new definition, not a declaration, thanks again stefanB
void Visitor::operator()( int data ) {
std::cout << "specialization" << std::endl;
}
int main()
{
Visitor v;
v( 5 ); // specialization
v( true ); // regular member function
v.operator()<bool>( true ); // generic template even if there is a non-templated overload
// operator() must be specified there (signature of the method) for the compiler to
// detect what part is a template. You cannot use <> right after a variable name
}
In your code there is not much of a difference, but if your code needs to pass the template parameter type it will get funnier:
template <typename T>
T g() {
return T();
}
template <>
int g() {
return 0;
}
int g() {
return 1;
}
int main()
{
g<double>(); // return 0.0
g<int>(); // return 0
g(); // return 1 -- non-templated functions take precedence over templated ones
}

What you have here is function overloading; to obtain template specialization, you indeed need the template <> syntax. However, you should be aware that these two approaches, even if they may seem identical, are subtly different, and even the compiler might get lost when choosing the right function to call. Listing all the possible cases would be a little too long for this answer, but you might want to check Herb Sutter GoTW #49 on the subject.

Oh, it'll compile. It just won't be a template function. You'll have a regular non-template function instead of a template specialization.
It's safe, and actually likely what you want as well. The Visitor pattern is normally implemented by overloading. Specializing function templates isn't really a good idea anyway.

What you did is not template serialization, but function overloading. It is safe.
P.S. It's difficult to say whether it's correct or not, without knowing what you're trying to achieve. Keep in mind that no matter is it template or overloaded function, your operator will be chosen in compile time. If you need to run-time dispatch, you need polymorphism, not overloading. Well, you probably know it anyway; just in case.

You have
void operator()(bool b) that is non
templated function
template< typename T > void
operator()(T t) which is a separate
base template that overloads the
above
You could have a full specialization of the second one as in template<> void operator(int i) which would only be considered when void operator()(bool b) did not match.
The specialization of base template is used to select which of the base template methods to call. However in your case you have a non-templated method that will get considered first.
The article Why Not Specialize Function Templates? gives quite good explanation of how the method is selected.
In sumary:
Non template functions are
considered first (this is your plain
operator()(bool) above)
Function base templates get checked
second (this is your templated
function), the most specialized base-template is selected and then if it has specialization for the exact types that specialization is used otherwise the base template is used with 'the correct' types (see explanation in the article)
Example:
#include <iostream>
using namespace std;
struct doh
{
void operator()(bool b)
{
cout << "operator()(bool b)" << endl;
}
template< typename T > void operator()(T t)
{
cout << "template <typename T> void operator()(T t)" << endl;
}
};
// note can't specialize inline, have to declare outside of the class body
template<> void doh::operator()<>(int i)
{
cout << "template <> void operator()<>(int i)" << endl;
}
template<> void doh::operator()<>(bool b)
{
cout << "template <> void operator()<>(bool b)" << endl;
}
int main()
{
doh d;
int i;
bool b;
d(b);
d(i);
}
You get calls to:
operator()(bool b) <-- first non template method that matches
template <> void operator()(int i) <-- the most specialized specialization of templated function is called

Related

Specialisation of member function templates in c++

I want to create a generic class containing a method displaying one message if the type of the class is int and the other when it's double. Here's my code:
template<class T>
class A {
public:
template <T> void B();
};
template<class T>
void A<int>::B{
//some code here
}
template<class T>
void A<double>::B{
//some code here
}
I got the following errors:
'double': illegal type for non-type template parameter '__formal'
'A<int>::B': unable to match function definition to an existing declaration
Thanks in advance for any solutions.
A couple of things:
There's no reason for B to be a template. You want to specialize for A
B is a method. Methods accept parameters. When defining the method, you omitted the parenthesis ()
Template specialization always involves an empty template parameter <>
Code:
template<class T>
class A {
public:
void B();
};
template<>
void A<int>::B(){
std::cout << "A<int>::B" << std::endl;
}
template<>
void A<double>::B(){
std::cout << "A<double>::B" << std::endl;
}
Demo
If you feel compelled to make B a template, I should note that in general one does not perform template specialization on functions. This is primarily because they cannot be partially specialized, and it's almost always better to write an overload. In your case, B takes no arguments, so there's some argument to be made in favor of specialization.
More often than not, one would use a tag dispatching approach instead, coupled with a helper function so that they can choose their desired function by taking advantage of overloading instead. Here's a simple example of tag dispatching for your case:
template<class T>
class A {
public:
template<class U>
void B()
{
B(ATag<U>{});
}
private:
template<class U>
struct ATag{};
void B(ATag<int>)
{
std::cout << "B<int>" << std::endl;
}
void B(ATag<double>)
{
std::cout << "B<double>" << std::endl;
}
};
tag dispatch demo

overloading function and inheritance

I am trying to overload some template function to perform specific action if I call it using a given class MyClass or any derived class MyClassDer. Here is the code:
#include <iostream>
struct MyClass {
virtual void debug () const {
std::cerr << "MyClass" << std::endl;
};
};
struct MyClassDer : public MyClass {
virtual void debug () const {
std::cerr << "MyClassDer" << std::endl;
};
};
template <typename T> void func (const T& t) {
std::cerr << "func template" << std::endl;
}
void func (const MyClass& myClass) {
std::cerr << "func overloaded" << std::endl;
myClass.debug ();
}
int main(int argc, char **argv) {
func (1);
MyClass myClass;
func (myClass);
MyClassDer myClassDer;
func (myClassDer);
}
The output is:
func template
func overloaded
MyClass
func template
func (myClassDer) calls the template function instead of void func (const MyClass& myClass). What can I do to get the expected behavior?
Thanks
This is just how overload resolution works. When lookup completes it finds both the template and the function. The template types are then deduced and overload resolution starts. In the case of an argument of type MyClass the two candiates are:
void func<MyClass>(MyClass const&);
void func(MyClass const&);
Which are equally good matches for the arguments, but the second being a non-template is preferred. In the case of MyClassDer:
void func<MyClassDer>(MyClassDer const&);
void func(MyClass const&);
In this case the first is a better candidate than the second one, as the second one requires a derived-to-base conversion and that is picked up.
There are different approaches to direct dispatch to hit your code. The simplest is just coercing the type of the argument to be MyClass and thus fallback to the original case:
func(static_cast<MyClass&>(myClassDer));
While simple, this needs to be done everywhere and if you forget in just one place, the wrong thing will be called. The rest of the solutions are complex and you might want to consider whether it would not be better to just provide different function names.
One of the options is using SFINAE to disable the template when the type is derived from MyClass:
template <typename T>
typename std::enable_if<!std::is_base_of<MyClass,MyClassDer>::value>::type
func(T const & t) { ... }
In this case, after lookup, the compiler will perform type deduction, and it will deduce T to be MyClassDer, it will then evaluate the return type of the function (SFINAE could also be applied to another template or function argument). The is_base_of will yield false and the enable_if won't have a nested type. The function declaration will be ill-formed and the compiler will drop it, leaving the resolution set with a single candidate, the non-template overload.
Another option would be providing a single template interface, and dispatching internally to either a template or the overload (by a different name) using tag-dispatch. The idea is similar, you evaluate the trait inside the template and call a function with a type generated from that evaluation.
template <typename T>
void func_impl(T const&, std::false_type) {...}
void func_impl(MyClass const&, std::true_type) {...}
template <typename T>
void func(T const &x) {
func_impl(x,std::is_base_of<MyClass,MyClassDer>::type());
}
There are other alternatives, but those are two common ones and the rest are mainly based on the same principles.
Again, consider whether the problem is worth the complexity of the solution. Unless the call to func is itself done inside generic code, a simple change of the function name will solve the problem without unnecessarily adding complexity that you or the other maintainers might have problems maintaining.
For why your code didn't work: see #David's excellent explanation. To get it to work, you can use SFINAE ("Substition Failure is not an Errro) by adding a hidden template parameter Requires (the name is for documentation purposes only)
template <
typename T, typename Requires = typename
std::enable_if<!std::is_base_of<MyClass, T>::value, void>::type
>
void func (const T& t) {
std::cerr << "func template" << std::endl;
}
This will disable this template for overload resolution whenever T is equal to or derived from MyClass, and will select the regular function instead (for which Derived-to-Base conversions will be performed, in contrast to template argument deduction, which considers exact matches only). You can obviously play around with this and add several overloads with non-overlapping conditions inside the std::enable_if to have a fine-grained selection of function overloads that will be considered. But be careful, SFINAE is subtle!
Live Example.
Note: I wrote my SFINAE with C++11 syntax, using a default template parameter for function templates. In C++98 you need to add either a regular default parameter or modify the return type.
You can use SFINAE:
#include <type_traits>
template <typename T>
void func (const T& t, typename std::enable_if<!std::is_base_of<MyClass, T>::value>::type * = nullptr) {
std::cout << "func template" << std::endl;
}
template <
typename T
, typename = typename std::enable_if<std::is_base_of<MyClass, T>::value>::type
>
void func (const T& t) {
std::cout << "func overloaded" << std::endl;
t.debug ();
}
If you don't have C++11, boost provides the same functionality.
Live example
EDIT
This should work without C++11 (using boost):
#include "boost/type_traits.hpp"
template <typename T>
void func (const T& t, typename boost::enable_if<!boost::is_base_of<MyClass, T>::value>::type * = 0) {
std::cout << "func template" << std::endl;
}
template <typename T>
void func (const T& t, typename boost::enable_if<boost::is_base_of<MyClass, T>::value>::type * = 0) {
std::cout << "func overloaded" << std::endl;
t.debug ();
}
Polymorphism occurs in run-time, but choosing an overloaded function occurs in compile-time.
So, in compile time the best overload to accept MyClassDer is
func<MyClassDer> (const MyClassDer& t)
rather than
func<MyClass> (const MyClass& t)
then compiler chooses the first.
A possibility to solve the issue is:
func(static_cast<MyClass&>(myClassDer));
You will need to use polymorphism in order to call your template function. You need a reference to your base class:
int main(int argc, char **argv) {
func (1);
MyClass myClass;
func (myClass);
MyClassDer myClassDer;
MyClass* mc = &myClassDer;
func (*mc);
}
More polymorphism examples and details here
Its because your overloaded function's signature is,
void func (const MyClass& myClass)
{
std::cerr << "func overloaded" << std::endl;
myClass.debug ();
}
i.e it wants MyClass as its parameter and you are calling it using MyClassDer. So at compile time it resolves the other overloaded function and links with that. As the other function is templated there is no problem for compiler to link with that.
So if you want to pass a MyClassDer object, you could still do it using polymorphism.
MyClass *myClassDer = new MyClassDer;
func(*myClassDer);
Just cast it to the base type:
MyClassDer myClassDer;
func(static_cast<MyClass&>(myClassDer));
MyClass *myClassDer = new MyClassDer;
func(*myClassDer);
delete myClassDer;

Specialized function in non specialised Template class

Please refer to the below code
Specialized function in non specialized Template class
Is it possible to write a specialized function foo, for non specialized template class MyClass [Line Number 7] ? If yes, then, what is the syntax for the same.
Regards,
Atul
This can be done if you create a full specialization of the class template. Just refer to the answer in this question: If I want to specialise just one method in a template, how do I do it?
Otherwise if you want to have a given function with the same signature have two different behaviors depending on the instantiated version of the class, and that instantiation is a partial specialization of the template class, you will have to make a separate specialization of the template class.
Keep in mind that if you want to avoid redundant code in this second case, you can always create a base template class that will have the functionality that will not change, and then create derived template classes that will contain the unique functionality necessary for each partial specialization.
Look at my example below, I have tried answer your question (if I guessed right) in the simplest code possible by me:
#include <iostream>
using namespace std;
template<typename T>
class Some
{
public:
template<typename U> void foo(U val);
};
template<typename T>
template<typename U>
void Some<T>::foo(U val)
{
cout << "Non specialized" << endl;
}
template<>
template<>
void Some<char>::foo(char val)
{
cout << "Char specialized" << endl;
}
int main()
{
Some<int> t1;
t1.foo(5);
Some<char> t2;
t2.foo('c');
return 0;
}
The important thing to note here is that "You cannot specialize your class and function Independently" i.e you have to specialize both at the same time as done in the example.
Also, with this you lose the opportunity to specialize your class for that data type "char" in this case. (Need to confirm on this).
UPDATE :: Confirmed on point 2.
If you wanted to specialize MyClass< bool >::Foo, it would look like this:
template <>
void MyClass<bool>::Foo(bool A)
{
// code goes here
}
If you are asking that,
(1) you want a function Foo() which doesn't take any argument and
returns void inside MyClass
(2) This Foo() should be exclusive to the MyClass when the
template type is bool, i.e. only for MyClass<bool>
then here is the way:
template<class Precision>
class MyClass {
...
public:
...
void Foo (); // don't implement here
};
...
template<>
void MyClass<bool>::Foo () // implementing only for 'MyClass<bool>'
{ // invoking for other 'MyClass<>' will result in compiler error
...
}

Differences between template specialization and overloading for functions?

So, I know that there is a difference between these two tidbits of code:
template <typename T>
T inc(const T& t)
{
return t + 1;
}
template <>
int inc(const int& t)
{
return t + 1;
}
and
template <typename T>
T inc(const T& t)
{
return t + 1;
}
int inc(const int& t)
{
return t + 1;
}
I am confused as to what the functional differences between these two are. Can someone show some situations where these snippits act differently from each other?
I can only think of a few differences - here are some examples that don't necessarily cause harm (i think). I'm omitting definitions to keep it terse
template <typename T> T inc(const T& t);
namespace G { using ::inc; }
template <> int inc(const int& t);
namespace G { void f() { G::inc(10); } } // uses explicit specialization
// --- against ---
template <typename T> T inc(const T& t);
namespace G { using ::inc; }
int inc(const int& t);
namespace G { void f() { G::inc(10); } } // uses template
That is because specializations are not found by name lookup, but by argument matching, so a using declaration will automatically consider a later introduced specialization.
Then, you of course cannot partially specialize function templates. Overloading however accomplishes something very similar by partial ordering (using different types now, to make my point)
template <typename T> void f(T t); // called for non-pointers
template <typename T> void f(T *t); // called for pointers.
int a;
void e() {
f(a); // calls the non-pointer version
f(&a); // calls the pointer version
}
That wouldn't be possible with function template explicit specialization. Another example is when references are involved, which causes template argument deduction to look for an exact match of the types involved (modulo base/derived class relationships and constness):
template<typename T> void f(T const &);
template<> void f(int * const &);
template<typename T> void g(T const &);
void g(int * const &);
int a[5];
void e() {
// calls the primary template, not the explicit specialization
// because `T` is `int[5]`, not `int *`
f(a);
// calls the function, not the template, because the function is an
// exact match too (pointer conversion isn't costly enough), and it's
// preferred.
g(a);
}
I recommend you to always use overloading, because it's richer (allows something like partial specialization would allow), and in addition you can place function in whatever namespace you want (although then it's not strictly overloading anymore). For example, instead of having to specialize std::swap in the std:: namespace, you can place your swap overload in your own namespace and make it callable by ADL.
Whatever you do, never mix specialization and overloading, it will be a hell of a mess like this article points out. The Standard has a lovely paragraph about it
The placement of explicit specialization declarations for function templates, class templates, member functions of class templates, static data members of class templates, member classes of class templates, member class templates of class templates, member function templates of class templates, member functions of member templates of class templates, member functions of member templates of non-template classes, member function templates of member classes of class templates, etc., and the placement of partial specialization declarations of class templates, member class templates of non-template classes, member class templates of class templates, etc., can affect whether a program is well-formed according to the relative positioning of the explicit specialization declarations and their points of instantiation in the translation unit as specified above and below. When writing a specialization, be careful about its location; or to make it compile will be such a trial as to kindle its self-immolation.
Template specialization is more generic than just overloading. You can specialize things like classes rather than just simple functions. Overloading only applies to functions.
UPDATE: To clarify more per AraK's comment, you are really comparing apples and oranges here. Function overloading is used to introduce the ability to have different functions share a single name, if they have different signatures. Template specialization is used to define a specific code snippet for a specific type parameter. You can't have a template specialization if you don't have a template. If you remove the first piece of code that declares the generic template, you'll receive a compile time error if you try to use template specialization.
So, the goal of template specialization is pretty different from a function overload. They just happen to behave similarly in your example while they are fundamentally different.
If you provide an overload, you are declaring an independent method that happens to have the same name. You are not preventing the template to be used with the specific type parameter. To demonstrate this fact, try:
template <typename T>
T inc(const T& t)
{
return t + 1;
}
int inc(const int& t)
{
return t + 42;
}
#include <iostream>
int main() {
int x = 0;
x = inc<int>(x);
std::cout << "Template: " << x << std::endl; // prints 1.
x = 0;
x = inc(x);
std::cout << "Overload: " << x << std::endl; // prints 42.
}
As you can see, in this example, there are two distinct inc functions for int values: inc(const int&) and inc<int>(const int&). You couldn't expand the generic template using int if you had used template specialization.
One such example:
#include <cstdio>
template <class T>
void foo(T )
{
puts("T");
}
//template <>
void foo(int*)
{
puts("int*");
}
template <class T>
void foo(T*)
{
puts("T*");
}
int main()
{
int* a;
foo(a);
}
It is actually suggested that you use non-template overloads for functions and leave specialization for classes. It is discussed at greater length in Why Not Specialize Function Templates?
AFAIK there is no functional difference. All I can add is that if you have both a template function specialisation and an ordinary function defined then there is no overload ambiguity as the ordinary function is favoured.
Just to elaborate on the first point mentioned by litb in his answer. Specializations are only checked once overload resolution has actually selected a primary template. The result can lead to some surprises where a function is overloaded and has explicit specializations:
template <typename T> void foo (T); // Primary #1
template <> void foo<int*> (int*); // Specialization of #1
template <typename T> void foo (T*); // Primary #2
void bar (int * i)
{
foo(i);
}
When choosing which function to call, the following steps take place:
Name lookup finds both primary templates.
Each template is specialized and overload resolution attempts to select a best function based on conversions between the arguments and parameters.
In thise case, there is no difference in the quality of the conversions.
Partial ordering rules are then used to select the most specialized template. In this case that is the second parimary "foo(T*)".
Only after these steps, when the best function has been selected will explicit specializations of the selected function be considered. (In this case primary #2 has none so none are considered).
The only way to call the above explicit specialization here, is to actually use explicit template arguments in the call:
void bar (int * i)
{
foo<int*> (i); // expliit template argument forces use of primary #1
}
A good rule of thumb is to try to avoid having overloads that are also explicily specialized, as the resulting rules are pretty complex.

How to call a templated function if it exists, and something else otherwise?

I want to do something like
template <typename T>
void foo(const T& t) {
IF bar(t) would compile
bar(t);
ELSE
baz(t);
}
I thought that something using enable_if would do the job here, splitting up foo into two pieces, but I can't seem to work out the details. What's the simplest way of achieving this?
There are two lookups that are done for the name bar. One is the unqualified lookup at the definition context of foo. The other is argument dependent lookup at each instantiation context (but the result of the lookup at each instantiation context is not allowed to change behavior between two different instantiation contexts).
To get the desired behavior, you could go and define a fallback function in a fallback namespace that returns some unique type
namespace fallback {
// sizeof > 1
struct flag { char c[2]; };
flag bar(...);
}
The bar function will be called if nothing else matches because the ellipsis has worst conversion cost. Now, include that candidates into your function by a using directive of fallback, so that fallback::bar is included as candidate into the call to bar.
Now, to see whether a call to bar resolves to your function, you will call it, and check whether the return type is flag. The return type of an otherwise chosen function could be void, so you have to do some comma operator tricks to get around that.
namespace fallback {
int operator,(flag, flag);
// map everything else to void
template<typename T>
void operator,(flag, T const&);
// sizeof 1
char operator,(int, flag);
}
If our function was selected then the comma operator invocation will return a reference to int. If not or if the selected function returned void, then the invocation returns void in turn. Then the next invocation with flag as second argument will return a type that has sizeof 1 if our fallback was selected, and a sizeof greater 1 (the built-in comma operator will be used because void is in the mix) if something else was selected.
We compare the sizeof and delegate to a struct.
template<bool>
struct foo_impl;
/* bar available */
template<>
struct foo_impl<true> {
template<typename T>
static void foo(T const &t) {
bar(t);
}
};
/* bar not available */
template<>
struct foo_impl<false> {
template<typename T>
static void foo(T const&) {
std::cout << "not available, calling baz...";
}
};
template <typename T>
void foo(const T& t) {
using namespace fallback;
foo_impl<sizeof (fallback::flag(), bar(t), fallback::flag()) != 1>
::foo(t);
}
This solution is ambiguous if the existing function has an ellipsis too. But that seems to be rather unlikely. Test using the fallback:
struct C { };
int main() {
// => "not available, calling baz..."
foo(C());
}
And if a candidate is found using argument dependent lookup
struct C { };
void bar(C) {
std::cout << "called!";
}
int main() {
// => "called!"
foo(C());
}
To test unqualified lookup at definition context, let's define the following function above foo_impl and foo (put the foo_impl template above foo, so they have both the same definition context)
void bar(double d) {
std::cout << "bar(double) called!";
}
// ... foo template ...
int main() {
// => "bar(double) called!"
foo(12);
}
litb has given you a very good answer. However, I wonder whether, given more context, we couldn't come up with something that's less generic, but also less, um, elaborate?
For example, what types can be T? Anything? A few types? A very restricted set which you have control over? Some classes you design in conjunction with the function foo? Given the latter, you could simple put something like
typedef boolean<true> has_bar_func;
into the types and then switch to different foo overloads based on that:
template <typename T>
void foo_impl(const T& t, boolean<true> /*has_bar_func*/);
template <typename T>
void foo_impl(const T& t, boolean<false> /*has_bar_func*/);
template <typename T>
void foo(const T& t) {
foo_impl( t, typename T::has_bar_func() );
}
Also, can the bar/baz function have just about any signature, is there a somewhat restricted set, or is there just one valid signature? If the latter, litb's (excellent) fallback idea, in conjunction with a meta-function employing sizeof might be a bit simpler. But this I haven't explored, so it's just a thought.
I think litb's solution works, but is overly complex. The reason is that he's introducing a function fallback::bar(...) which acts as a "function of last resort", and then goes to great lengths NOT to call it. Why? It seems we have a perfect behavior for it:
namespace fallback {
template<typename T>
inline void bar(T const& t, ...)
{
baz(t);
}
}
template<typename T>
void foo(T const& t)
{
using namespace fallback;
bar(t);
}
But as I indicated in a comment to litb's original post, there are many reasons why bar(t) could fail to compile, and I'm not certain this solution handles the same cases. It certainly will fail on a private bar::bar(T t)
If you're willing to limit yourself to Visual C++, you can use the __if_exists and __if_not_exists statements.
Handy in a pinch, but platform specific.
EDIT: I spoke too soon! litb's answer shows how this can actually be done (at the possible cost of your sanity... :-P)
Unfortunately I think the general case of checking "would this compile" is out of reach of function template argument deduction + SFINAE, which is the usual trick for this stuff. I think the best you can do is to create a "backup" function template:
template <typename T>
void bar(T t) { // "Backup" bar() template
baz(t);
}
And then change foo() to simply:
template <typename T>
void foo(const T& t) {
bar(t);
}
This will work for most cases. Because the bar() template's parameter type is T, it will be deemed "less specialised" when compared with any other function or function template named bar() and will therefore cede priority to that pre-existing function or function template during overload resolution. Except that:
If the pre-existing bar() is itself a function template taking a template parameter of type T, an ambiguity will arise because neither template is more specialised than the other, and the compiler will complain.
Implicit conversions also won't work, and will lead to hard-to-diagnose problems: Suppose there is a pre-existing bar(long) but foo(123) is called. In this case, the compiler will quietly choose to instantiate the "backup" bar() template with T = int instead of performing the int->long promotion, even though the latter would have compiled and worked fine!
In short: there's no easy, complete solution, and I'm pretty sure there's not even a tricky-as-hell, complete solution. :(
//default
//////////////////////////////////////////
template <class T>
void foo(const T& t){
baz(t);
}
//specializations
//////////////////////////////////////////
template <>
void foo(const specialization_1& t){
bar(t);
}
....
template <>
void foo(const specialization_n& t){
bar(t);
}
Are you not able to use full specialisation here (or overloading) on foo. By say having the function template call bar but for certain types fully specialise it to call baz?