I want to have a function that takes a std::string and another that takes anything that is not a std::string.
So I have:
#include <iostream>
#include <string>
void foo(const std::string& str) {
std::cout << "string version called" << std::endl;
}
template<class T>
void foo(T&& str) {
std::cout << "template version called" << std::endl;
}
int main() {
foo(std::string{"hello"});
return 0;
}
The problem is that the templated version is called instead of the std::string version.
So how can I have a foo function that either takes anything or specifically a std::string?
The templated foo is using forwarding reference, when being passed temporary std::string like std::string{"hello"}, after the deduction the function parameter str would be std::string&&, it's a better match than the non-template foo which taking const std::string&.
You can impose restrictions on the template parameter to make it usable only when being passed non-std::strings. E.g.
template<class T>
std::enable_if_t<!std::is_same_v<std::decay_t<T>, std::string>>
foo(T&& str) {
std::cout << "template version called" << std::endl;
}
LIVE
Your problem is you are taking by forwarding reference. An rvalue binds to std::string&& better than std::string const&, so yourtemplate ks preferred.
Change it to
template<class T>
void foo(T const& str) {
std::cout << "template version called" << std::endl;
}
use typeid()
template <class T>
void foo(T &&str)
{
if (typeid(str) == typeid(string))
{
std::cout << "string version called" << std::endl;
}else{
std::cout << "template version called" << std::endl;
}
}
int main() {
foo(std::string{"hello"});
foo("hello");
return 0;
}
The problem with your code is that you are creating a temporary variable std::string{"Hello"} which is an exact match for T&& (better than std::string const&) and therefore the templated version is chosen. You could either
Specialise the template for std::string
template<typename T>
void foo(T t) {
// Your implementation for other data types
}
// Template specialisation for strings
template <>
void foo<std::string>(std::string str) {
// Your implementation for strings goes here
}
Overload the function and de-activate the template for std::string, std::string const&, std::string&&, ... For the latter you can use the std::decay<T> type trait struct to disable all of these versions at once in combination with std::is_same.
// Function overload for strings
void foo(std::string const& str) {
// Your implementation for strings goes here
}
// Template disabled for strings
template<class T>
typename std::enable_if<!std::is_same<std::decay<T>::type, std::string>::value>::type
foo(T&& t) {
// Your implementation for the other data types
}
You could compare the typeid or even better in C++17 there is a constexpr if available which could be combined with std::is_same<T>
template<class T>
void foo(T&& t) {
if constexpr (std::is_same_v<T, std::decay_t<std::string>>) {
// Your implementation for strings
} else {
// Your implementation for the other data types
}
}
Furthermore if you wanted to make something like
foo("Hello");
work as well (so instead of foo(std::string{"Hello"})) you could take it a step further also excluding any sort of char*
// Gets used for std::string as well as char*
void foo(std::string const& str) {
std::cout << "string version called" << std::endl;
}
// Disable template for any std::string and char*
template<class T>
typename std::enable_if<!std::is_same<typename std::decay<T>::type, std::string>::value &&
!std::is_same<typename std::decay<T>::type, char const *>::value &&
!std::is_same<typename std::decay<T>::type, char *>::value>::type
foo(T&& t) {
std::cout << "template version called" << std::endl;
}
In this case also foo("Hello") will call the overloaded std::string version. Without this any call without std::string{} will go to the templated version! Try it hereC++11 C++17.
Use an explicit specialization rather than an overloaded function.
template<>
void foo<std::string>(const std::string& str) {
...
I think that's right; explicit specializations of free functions was not original to C++98 but added later at some point.
(it's still a pain to get right, as your specialization has to match the actual type that was deduced for T, which may include const and & if those were not present in the argument list; I've used it effectively for plain pass-by-value types like when the special type is int)
In C++20, you could use a requires clause to make the template not apply for std::string. If requires is not available, you can do the same thing using enable_if.
You might also just write one function, but use constexpr if in the body to provide the special case. This prevents the overloading mechanism from getting involved at all, and lets you code the exact rules for determining the special case.
Update: something old and something new
In the original template specification, function templates could not be explicitly specialized and the idea was that you overload functions instead. You see why this doesn't work as intended: the template is always an exact match, even when the specific function would be called (using trivial conversions, adding const, passing by reference) if overloading just non-template functions.
The work-around was to make a dummy class template, holding a static member function. So, if you originally had a function template f and you needed to explicitly specialize it, move the function body into:
template <typename T>
struct C {
void f (const T&) { /* body goes here */ }
};
Now you can write an explicit specialization of C, and thus C::f:
template<>
struct C<std::string> {
static void f (const std::string&) { /* special code goes here */ }
};
and then, to retain compatibility with the existing code, write a new body for the (non-member) f that just calls C<T>::f.
Now, doing that today you would make it even better and use perfect forwarding.
template <typename T>
void f (const T&& param)
{
C<T>::f(std::forward<T>(param));
}
Now, look at how this differs from just being able to explicitly specialize a function. The template argument deduction is done on the wrapper call, and then the determined value of T is used for the class template instantiation, and then the final member function call does not do any deduction but rather will apply conversions as for normal function calls. It doesn't have the "always a perfect match" behavior. The exact form of the argument can vary; e.g. whether you are passing a value or a const reference.
In fact, thanks to perfect forwarding, it preserves the value category of the wrapper's call, and you can actually overload f within one of the explicit specializations! That is, you could have a separate form for rvalues, constants or non-const, etc.
Here, the wrapper function was declared with const which loses the ability to distinguish non-const parameters, but this makes it easy to have template argument deduction not include the const. You could add your own normalization step to transform the actual argument's type into the plain T you wanted, instead. In fact, you can add any metaprogramming logic you want, such as recognising base and derived classes, which is another issue that shows up with overloading and templates.
Related
I'm wondering if it's possible to pass a template function (or other) as an argument to a second function (which is not a template).
Asking Google about this only seems to give info about the opposite ( Function passed as template argument )
The only relevant page I could find was http://www.beta.microsoft.com/VisualStudio/feedbackdetail/view/947754/compiler-error-on-passing-template-function-as-an-argument-to-a-function-with-ellipsis
(not very helpful)
I'm expecting something like:
template<class N>void print(A input){cout << input;}
void execute(int input, template<class N>void func(N)){func(input)}
and then later call
execute(1,print);
So, can this be done or would another template have to be defined for execute() ?
Function templates represent an infinite overload set, so unless you have a target type that is compatible with a specialization, deduction of the function type always fails. For example:
template<class T> void f(T);
template<class T> void h(T);
void g() {
h(f); // error: couldn't infer template argument 'T'
h(f<int>); // OK, type is void (*)(int)
h<void(int)>(f); // OK, compatible specialization
}
From above we can see that the validity of the program demands that we specify the template arguments for the function template, when in general it isn't always intuitive to specify them. You can instead make print a functor with a generic overloaded call operator as an extra level of indirection:
struct print {
template<typename T>
void operator()(T&& x) const {
std::cout << x;
}
};
Now you can have execute accept any Callable and invoke it with the input:
template<class T, class Op>
void execute(T&& input, Op&& op) {
std::forward<Op>(op)(std::forward<T>(input));
}
void g() { execute(1, print{}); }
Generic lambdas (C++14) make this a lot more concise:
execute(1, [] (auto&& x) { std::cout << x; });
Execute would need to be a template- there's no way for the compiler to create a single version of execute that would work for any input type. Now if you specified what N is for this specific function- for example if you made the second parameter print- then it should be legal.
Recently I often encountered the problem, that I had to write a function which takes an input as a const reference. But at some point this function (usually a constructor) calls another function which could use the input as a move reference. For that reason I usually created a copy of the function to allow const reference and move reference, i.e.
#include <iostream>
class A {};
void foo(const A& a) { std::cout << "Reference" << std::endl; }
void foo( A&& a) { std::cout << "Move" << std::endl; }
void bar(const A& a) {
//Other things, which treat "a" as a const reference
foo(std::move(a));
}
void bar(A&& a) {
//Other things, which treat "a" as a const reference
foo(std::move(a));
}
int main() {
A a;
bar(a);
bar(A());
}
However it is obviously pretty ugly to copy bar two times with the only difference being the signature and the std::move. One alternative I know would be to make bar a tempalte function and to use std::forward, but I don't want to do that because it would allow any parameter type to be passed to bar (especially since in my real application bar is an implicit constructor).
So my question is: Is there any other way to forward a move reference through a function without writing it twice?
If you want to accept both rvalues and lvalues in a single function, retaining the possibility to restore the value category of its argument, you can use a forwarding-reference. You can easily restrict the type of arguments passed in utilizing the expression SFINAE technique, which in your case will verify if the call foo(std::forward<T>(a)) is well-formed. If not, that function will be excluded from the set of viable functions during the overload resolution:
Option #1
Hide the expression SFINAE in a trailing return type:
template <typename T>
auto bar(T&& a)
-> decltype(void(foo(std::forward<T>(a))))
{
//Other things, which treat "a" as a const reference
foo(std::forward<T>(a));
}
DEMO 1
Option #2
Hide the expression SFINAE in a template parameters list:
template <typename T,
typename = decltype(foo(std::forward<T>(std::declval<T&>())))>
void bar(T&& a)
{
//Other things, which treat "a" as a const reference
foo(std::forward<T>(a));
}
DEMO 2
The latter approach is especially useful for constructors (which don't specify a return type):
struct Bar
{
template <typename T,
typename = decltype(foo(std::forward<T>(std::declval<T&>())))>
Bar(T&& a)
{
foo(std::forward<T>(a));
}
};
DEMO 3
Perfect forwarding with SFINAE works and keeps the overload set unpolluted. You first have to decide what exactly should be checked, e.g. the type set this template should be invoked for or expressions that should be valid.
Here, both suffice - this code checks the type:
// Helper template:
template <typename T, typename U, typename R=void>
using enable_if_compatible = typename std::enable_if<std::is_same<U,
typename std::remove_cv<
typename std::remove_reference<T>::type>::type>::value, R>::type;
// Possible usage:
template <typename T>
enable_if_compatible<T, A> bar(T&& a)
{
//Other things, which treat "a" as a const reference
foo(std::forward<T>(a));
}
Demo.
The following one depends on the validity of the call to foo and should be more flexible.
template <typename T>
auto bar(T&& a) -> decltype(void(foo(std::forward<T>(a))))
{
//Other things, which treat "a" as a const reference
foo(std::forward<T>(a));
}
Demo.
One option is to add a templated version of bar that takes a pointer to foo and contains all of the common code that is currently in existing implementations of bar.
template<class T>
void bar(T&& a, void (*f)(T&&a))
{
//Other things, which treat "a" as a const reference
f(std::move(a));
}
void bar(const A& a)
{
bar<const A&>(a, foo);
}
void bar(A&& a)
{
bar(std::move(a), foo);
}
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;
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?
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