How to call one of two C++ template functions with condition - c++

There is a class with two member template functions: fun1(), fun2().
I want to call one of the functions decided by a const bool class member : willCallFun1.
There is a solution like fun() in the code, but the if-else branch will check every times while fun() is called. I want avoid branch.
Since when the Foo object is constructed, const bool willCallFun1 has been set, so which function of fun1 and fun2 will be used can already be determined.
class Foo {
public:
const bool willCallFun1;
Foo(bool b) : willCallFun1{b}{
}
template<typename T>
void fun1(T t) {
std::cout << "fun1 "<< t << "\n";
}
template<typename T>
void fun2(T t) {
std::cout << "fun2 "<< t << "\n";
}
template<typename T>
void fun(T t){
if (willCallFun1) fun1<T>(t);
else fun2<T>(t);
}
};
int main() {
Foo f1{true};
f1.fun(123);
f1.fun("hi");
Foo f2{false};
f2.fun(456);
f2.fun("hello");
}
If fun1, fun2 are non-template functions, I can add a new member in the class, such as a function pointer or std::function to bind one of them at the constructor.
I can't find a way to do it when they are template functions.
I would be very grateful if someone could answer.

Since you can't make willCallFun1 into a template parameter and use if constexpr to decide which function to call, you could create an array of member function pointers and lookup the correct one using willCallFun1 as an index variable.
template <typename T>
void fun(T t) {
using fun_sig = void(Foo::*)(T);
static constexpr fun_sig funs[] = {&Foo::fun2<T>, &Foo::fun1<T>};
(this->*funs[willCallFun1])(t);
}
Demo
I'd test if this is actually faster than having a simple if though. I've done this before with disappointing results.

Related

How to get a forwarding function to call a base template function that is declared after the forwarding function

I have a case where I need to have a forwarding function defined before a template base function is defined/declared. However, if I call the forwarding function (fwd) that in turn calls the base function test, it says that the base template function is not visible (see the code below). However, if test is called directly, everything works.
So my question is this, is it possible to have the forwarding function make a call to a base template function that is defined later in the compilation unit (before it is used but after the forwarding function)? If not, do I have any options to work around this? I would like to avoid a forward declaration before fwd as that would make use of the library I am developing harder. I think if I could force fwd to be inline it would solve the problem but I have no way of doing that unless a macro is used.
#include <iostream>
#include <vector>
template<typename T, std::enable_if_t<std::is_scalar<T>::value, int> = 0>
void test(const T& t)
{
std::cout << "Scalar" << std::endl;
}
template<typename T>
void fwd(T&& t)
{
test(std::forward<T>(t));
}
template<typename T>
void test(const std::vector<std::vector<T>>& t)
{
std::cout << "vector vector of T" << std::endl;
}
int main(int argc, const char * argv[]) {
test(1); //OK, prints Scalar
fwd(1); //OK, prints Scalar
test(std::vector<std::vector<int>>()); //OK, prints vector vector of T
// Causes compile error: Call to function 'test' that is neither visible in the template definition
// nor found by argument dependent lookup
fwd(std::vector<std::vector<int>>());
return 0;
}
The name test in fwd is a dependent name. It will be resolved into two steps:
Non-ADL lookup examines function declarations ... that are visible from the template definition context.
ADL examines function declarations ... that are visible from either the template definition context or the template instantiation context.
Given that the relative order of test and fwd should not be changed, one possible solution is to use a fake tag struct in the namespace to activate ADL:
namespace my_namespace
{
struct Tag {};
template<typename T, std::enable_if_t<std::is_scalar<T>::value, int> = 0>
void test(const T& t, Tag = Tag{}) {
std::cout << "Scalar" << std::endl;
}
template<typename T>
void fwd(T&& t) {
test(std::forward<T>(t), Tag{});
}
template<typename T>
void test(const std::vector<std::vector<T>>& t, Tag = Tag{}) {
std::cout << "vector vector of T" << std::endl;
}
}
int main() {
my_namespace::test(std::vector<std::vector<int>>()); // OK
my_namespace::fwd(std::vector<std::vector<int>>()); // OK, too
}
Demo
Depending on what test overloads you have, another solution might be to wrap these functions into structs and use template specialization instead of function overloading:
template<class T>
struct Test {
static void op(const T& t) {
std::cout << "Scalar" << std::endl;
}
};
template<typename T>
void fwd(T&& t) {
Test<std::decay_t<T>>::op(std::forward<T>(t));
}
template<class T>
struct Test<std::vector<std::vector<T>>> {
static void op(const std::vector<std::vector<T>>& t) {
std::cout << "vector vector of T" << std::endl;
}
};
int main() {
fwd(1);
fwd(std::vector<std::vector<int>>());
}
Demo

Using class template argument deduction to make a static interface

I want to create some macros to create static interfaces for templated argument passing, storage, etc. I'm using class template argument deduction, but I'm hitting a wall.
#include <iostream>
template <typename Type>
struct Person
{
Type &object;
Person(Type &object) : object(object) {}
void walk(unsigned steps)
{
object.walk(steps);
}
void talk(const std::string &words)
{
object.talk(words);
}
};
struct MySelf
{
void walk(unsigned steps)
{
std::cout << "walking: " << steps << std::endl;
}
void talk(const std::string &words) const
{
std::cout << "talking: " << words << std::endl;
}
};
template <typename Type>
void testNConst(Person<Type> object)
{
object.walk(50);
object.talk("testing");
}
template <typename Type>
void testConst(Person<const Type> object)
{
object.talk("testing");
}
int main()
{
MySelf myself;
testNConst(Person{myself}); // compiles
testNConst(myself); // does not compile
testConst(myself); // does not compile
return 0;
}
Output:
../../../../src/py.com.personal/other/hanaTest/main.cpp:53:5: error: no matching function for call to 'testNConst'
testNConst(myself); // does not compile
^~~~~~~~~~
../../../../src/py.com.personal/other/hanaTest/main.cpp:35:6: note: candidate template ignored: could not match 'Person<type-parameter-0-0>' against 'MySelf'
void testNConst(Person<Type> object)
^
../../../../src/py.com.personal/other/hanaTest/main.cpp:54:5: error: no matching function for call to 'testConst'
testConst(myself); // does not compile
^~~~~~~~~
../../../../src/py.com.personal/other/hanaTest/main.cpp:42:6: note: candidate template ignored: could not match 'Person<const type-parameter-0-0>' against 'MySelf'
void testConst(Person<const Type> object)
^
2 errors generated.
Any ideas?
Class template argument deduction applies only to creating objects (variable declarations, etc.).
It simply does not apply to either function parameters or function return types. You cannot call testNConst(myself) because myself is not a Person<T> for some T - normal function deduction rules apply.
In short:
template <typename T> struct X { X(T ); };
X x = 42; // ok, ctad here
template <typename T>
void foo(X<T> );
foo(42); // error, ctad doesn't apply here
X bar() { return 42; } // error, ctad doesn't apply here either
An other approach could be using the curiously recurring template pattern (CRTP), inherit from the interface, which takes the type itself as the template parameter, remember you can downcast with static_cast and there is no problem with overload resolution, when using the interface as the parameter. You must know that you cannot use an object of type Person, if it is not subclassed. So you must pass the objects by reference to functions (which is faster than copying the object)...
Instead of the object of type Type living inside Person, the Interface lives inside the Type itself. (The interface does not have any members, when empty structs are inherited from, there is no additional memory overhead, the sizeof MySelf is the same as without the inheritance). With this approach never use Person<Type> without const&, & or && in a parameterlist.
#include <iostream>
template <typename Type>
struct Person
{
/// this returns the subclass-object
Type &object() { return static_cast<Type&>(*this); }
Type const &object() const { return static_cast<Type const&>(*this); }
void walk(unsigned steps)
{
object().walk(steps);
}
void talk(const std::string &words) const /// const was eventually missing
{
object().talk(words);
}
protected:
~Person() = default; /// this disallows the user to construct an instance of this class that is not used as a base object
};
struct MySelf : Person<MySelf>
{
void walk(unsigned steps)
{
std::cout << "walking: " << steps << std::endl;
}
void talk(const std::string &words) const
{
std::cout << "talking: " << words << std::endl;
}
};
template <typename Type>
void testNConst(Person<Type>& object) /// works fine with instances of MySelf and Person<MySelf>
{
object.walk(50);
object.talk("testing");
}
template <typename Type>
void testConst(Person<Type> const& object)
{
object.talk("testing");
}
int main()
{
MySelf myself;
testNConst(myself); // compiles
testConst(myself); // compiles
return 0;
}
Some other tips
always pass objects by reference if you want to change the object
always pass objects by const reference if you do not want to change the object
Edit
a protected destructor avoids that the class is instantiated without a derived class, this prevents the programmer from otherwise invoke undefined behavior (the static_cast<Type&> is the critical point).

Storing member function pointer from arbitrary class as class instance variable

There are a few questions on SO that address passing function pointers as parameters/arguments (here, here, here, etc.). In fact, I asked a related question the other day. However, this question is a little different.
My problem is that I am writing a class that I want to be extremely flexible.
What I have now works for non-member functions. It is posted below
template <typename T>
class MyClass
{
private:
typedef double (*firstFunctionPtr) (const T &var);
typedef bool (*secondFunctionPtr)(const T &var);
// Function pointers as member variables
firstFunctionPtr _firstFunc;
secondFunctionPtr _secondFunc;
public:
inline MyClass(firstFunctionPtr firstFunc,
secondFunctionPtr secondFunc);
};
template<typename T>
MyClass<T>::MyClass(firstFunctionPtr firstFunc, secondFunctionPtr secondFunc) :
_firstFunc(firstFunc),
_secondFunc(secondFunc),
{}
However, this falls apart when I need to initialize with a pointer to a member function of some other, arbitrary, class, which, unfortunately for me, happens to be a common use case for my purposes.
This answer suggests that
In a proper C++ interface you might want to have a look at having your function take templated argument for function objects to use arbitrary class types.
However, I have not been able to make this compile. I've tried templating my typedefs (using the C++11 aliasing approach), and I've tried adding a second template parameter to the class to handle the calling class of those member functions, but neither approach has worked.
This Q/A seems to be getting towards what I'm trying to do, but I can't make heads or tails of it.
Can someone please explain how I might modify my class to handle arbitrary member functions pointers being passed in?
Furthermore, is it possible to make it so that it can handle either arbitrary member functions or non-member functions?
Lastly, is it possible to do this with templates?
For the record, I'm trying to avoid using the functional header, but it may be a fool's errand not to use it.
If you want MyClass to be a template that can hold both free function
pointers of types:
double (*)(const T &var);
bool (*)(const T &var);
for some parameter type T, or alternatively member-function
pointers of types:
double (C::*)(const T &var);
bool (C::*)(const T &var);
for some parameter types C and T then, MyClass must be parameterized
by both T and C and you require two specializations:
Where C is some non-class type
Where C is any class type
In case (1), the non-class type C cannot possibly have member functions,
so that one will implement the free-function pointer specialization.
In case (2), the class C could be one that has member functions, so that one
will implement the member-function pointer specialization.
The obvious choice for a non-class type C is void. So we can make C
default to void:
Primary template
template<typename T, typename C = void>
struct MyClass;
So that:
MyClass<T>
will be the free function pointer specialization for T, and:
MyClass<T,C>
for any C other than void, will be the member-function pointer specialization.
As you may know you can use std::enable_if
and SFINAE to make the compiler
chose one specialization of a class template or another, depending on whether one
of its template parameters U satisfies some compiletime test. You could take
that approach here, but another one is available that does not require that apparatus:
Starting with the primary template, we would just like to have:
Free function specialization
template<typename T>
struct MyClass<T>
{
... for free function pointers ...
};
and:
Member function specialization
template<typename T, typename C>
struct MyClass<T,C>
{
... for member function pointers ...
};
But we can't have just that, because the member function "specialization" has exactly
the same template parameters as the primary template. Which means it isn't
a specialization, and the compiler won't allow it.
You can easily remove that problem, however, simply by giving the primary
template one more defaulting template parameter that it doesn't need, but whose
presence allows both those specializations to stand.
New primary template
template <typename T, typename C = void, typename Default = void>
struct MyClass;
So here is an illustrative solution:
// Primary template
template <typename T, typename C = void, typename Default = void>
struct MyClass;
// Free function specialization
template <typename T>
struct MyClass<T>
{
using firstFunctor_t = double(*)(T const &);
using secondFunctor_t = bool(*)(T const &);
MyClass(firstFunctor_t firstFunc, secondFunctor_t secondFunc)
: _firstFunc(firstFunc),
_secondFunc(secondFunc)
{}
double callFirst(T const & var) {
return _firstFunc(var);
}
bool callSecond(T const & var) {
return _secondFunc(var);
}
private:
firstFunctor_t _firstFunc;
secondFunctor_t _secondFunc;
};
// Member function specialization
template <typename T, typename C>
struct MyClass<T,C>
{
using firstFunctor_t = double(C::*)(T const &);
using secondFunctor_t = bool(C::*)(T const &) const;
MyClass(firstFunctor_t firstFunc, secondFunctor_t secondFunc)
: _firstFunc(firstFunc),
_secondFunc(secondFunc)
{}
double callFirst(C & obj, T const & var) {
return (obj.*_firstFunc)(var);
}
double callFirst(C const & obj, T const & var) {
auto & o = const_cast<C&>(obj);
return (o.*_firstFunc)(var);
}
bool callSecond(C & obj, T const & var) {
return (obj.*_secondFunc)(var);
}
bool callSecond(C const & obj, T const & var) {
auto & o = const_cast<C&>(obj);
return (o.*_secondFunc)(var);
}
private:
firstFunctor_t _firstFunc;
secondFunctor_t _secondFunc;
};
In the member function specialization, notice a couple of points that you might
not have considered:-
I decided that the second member function I want to store shall be a
const member function. It's more than likely that a member function of C
that take a T const & argument and returns bool will be a const member
function, isn't it? And if so, then that const-ness has to be part of
the member-function type definition that I use in the specialization:
using secondFunctor_t = bool(C::*)(T const &) const;
or attempts to instantiate the specialization with any bool (C::*)(T const &) const
will fail to compile.
Also, I have provided two overloads for each of MyClass<T,C>::callFirst
and MyClass<T,C>::callSecond, one with arguments:
C & obj, T const & var
and another with arguments:
C const & obj, T const & var
Without the second, attempts to call either MyClass<T,C>::callFirst
or MyClass<T,C>::callSecond with an obj that is const will fail to
compile.
For program to demo this solution you can append:
#include <iostream>
#include <string>
double foo(std::string const & s)
{
return std::stod(s);
}
bool bar(std::string const & s)
{
return s.size() > 0;
}
struct SomeClass
{
SomeClass(){};
double foo(std::string const & s) {
return ::foo(s);
}
bool bar(std::string const & s) const {
return ::bar(s);
}
};
int main()
{
MyClass<std::string> my0{foo,bar};
std::cout << std::boolalpha;
std::cout << my0.callFirst("1.11") << std::endl;
std::cout << my0.callSecond("Hello World") << std::endl;
MyClass<std::string,SomeClass> my1{&SomeClass::foo,&SomeClass::bar};
SomeClass thing;
std::cout << my1.callFirst(thing,"2.22") << std::endl;
std::cout << my1.callSecond(thing,"Hello World") << std::endl;
SomeClass const constThing;
std::cout << my1.callFirst(constThing,"3.33") << std::endl;
std::cout << my1.callSecond(constThing,"Hello World") << std::endl;
return 0;
}
See it live
You said that you want this template to be "extremely flexible". The
illustrated solution is fitted to your example, but you might be
interested in know that it isn't nearly as flexible as you could get.
For both free functions and member functions, with additional variadic template
parameters, your template could store and call [member] functions with
arbitary return types and arbitary numbers of arguments of arbitrary types.
See this question and
answer.
I will sugest to create a helper object which will store the type you want to work with:
template <typename RETURN, typename TYPE, typename CLASS>
struct function_pointer
{ using type_t = RETURN (CLASS::*)(const TYPE &); };
template <typename RETURN, typename TYPE>
struct function_pointer<RETURN, TYPE, std::nullptr_t>
{ using type_t = RETURN (*)(const TYPE &); };
This type will create a member-function-pointer if a class is provided as third parameter and a function-pointer otherwise. Now, we can use this helper in MyClass:
template <typename T, typename CLASS = std::nullptr_t>
class MyClass
{
using firstFunctionPtr = typename function_pointer<double, T, CLASS>::type_t;
using secondFunctionPtr = typename function_pointer<bool, T, CLASS>::type_t;
// Function pointers as member variables
firstFunctionPtr _firstFunc;
secondFunctionPtr _secondFunc;
public:
inline MyClass(firstFunctionPtr firstFunc, secondFunctionPtr secondFunc) :
_firstFunc(firstFunc),
_secondFunc(secondFunc)
{}
void call_first(CLASS &c, const T&v) { (c.*_firstFunc)(v); }
void call_second(CLASS &c, const T&v) { (c.*_secondFunc)(v); }
void call_first(const T&v) { (_firstFunc)(v); }
void call_second(const T&v) { (_secondFunc)(v); }
};
I've added call_* functions just to show a use case, which will be as below:
// Some class with the expected function signatures
struct S1
{
int i = 0;
double d(const int &) { std::cout << i << ' ' << __PRETTY_FUNCTION__ << '\n'; return{}; }
bool b(const int &) { std::cout << i << ' ' << __PRETTY_FUNCTION__ << '\n'; return{}; }
};
// Another class with the expected function signatures
struct S2
{
double d(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
bool b(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
};
// Free function with which could have the expected function signature
template <typename R>
R f(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
Using MyClass with an arbitrary class (S1):
S1 a{1}, b{2};
S2 c, d;
MyClass<int, S1> MCiS1(&S1::d, &S1::b);
MCiS1.call_first(a, 111); // Prints -> 1 double S1::d(const int&)
MCiS1.call_second(b, 222); // Prints -> 2 bool S1::b(const int&)
MCiS1.call_first(c, 111); // Error decltype(c) is not S1.
MCiS1.call_second(d, 222); // Error decltype(d) is not S1.
Using MyClass with a different class (S2):
MyClass<int, S2> MCiS2(&S2::d, &S2::b);
MCiS2.call_first(c, 111); // Prints -> double S2::d(const int&)
MCiS2.call_second(d, 222); // Prints -> bool S2::b(const int&)
MCiS2.call_first(a, 111); // Error decltype(c) is not S2.
MCiS2.call_second(b, 222); // Error decltype(d) is not S2.
Using MyClass with non-member functions:
MyClass<int> MCi(f<double>, f<bool>);
MCi.call_first(111); // Prints -> R f(const int&) [with R = double]
MCi.call_second(222); // Prints -> R f(const int&) [with R = bool]
Check the live demo Here.
All you need to do is bind the object instance for the member function pointer as a first argument.
struct foo {
float bar1(const type &var);
bool bar2(const type &var);
};
foo my_foo;
auto f1 = std::bind(&foo::bar1, my_foo, _1);
auto f2 = std::bind(&foo::bar2, my_foo, _1);
MyClass<type> my_obj(f1, f2);

bind binded function as argument

I have a class foo with a method bar which takes something callable (function-pointer/ functor). this callable something should be passed to another method doit as an binded element with a third method bar_cb method.
#include <functional>
#include <iostream>
class foo {
public:
template<typename T>
void bar(T&& t) {
std::cout << "bar\n";
doit(std::bind(&foo::template bar_cb<T>, this, std::forward<T>(t)));
}
template<typename T>
void doit(T&& t) {
std::cout << "doit\n";
t();
}
template<typename T>
void bar_cb(T&& t) {
std::cout << "bar_cb\n";
t();
}
};
void lala() {
std::cout << "lala\n";
}
class functor {
public:
void operator()() {
std::cout << "functor::operator()\n";
}
};
int main() {
foo f;
functor fn;
f.bar(fn);
f.bar(std::bind(lala)); // error
return 0;
}
This works fine for functors but not for binded functions as argument for foo::bar (lala in my example). Is it possible to pass an unknowable type to a method and bind it in this method as an argument to another (and if so how)?
I know I could wrap a functor (std::function for example) around the function but since I can call an unknowable type I think there is a way to also bind it (I think I'm just missing something simple).
Here a link to an example.
The primary problem is that your bar_cb(T&&) doesn't deduce the template argument because the template argument is actually specified when using &foo::template bar_cb<X> with some template argument X. The bind() expression will, however, copy the bound function, i.e., it may or may not have the type which would be deduced. Also, std::bind() will not pass bind()-expression through but will rather call them!
The easiest work around is to not use std::bind() to bind the function but rather to use a lambda function:
template<typename T>
void bar(T&& t) {
std::cout << "bar\n";
doit([=](){ this->bar_cb(t); });
}
Doing so let's the compiler deduce the correction argument type for bar_cb() (with C++14 you may want to use the capture [this,t = std::forward<T>(t)] although your bar_cb() still won't see an rvalue).
To pass an already bind()-expression through another bind()-expression, without having bind() consider the inner bind()-expression a bind()-expression you need to make it look as if it is not a bind()-expression. You could do so with a thin function wrapper:
template <typename Fun>
class unbinder {
Fun fun;
public:
template <typename F>
unbinder(F&& fun): fun(std::forward<F>(fun)) {}
template <typename... Args>
auto operator()(Args&&... args) const
-> decltype(fun(std::forward<Args>(args)...)) {
return fun(std::forward<Args>(args)...);
}
};
template <typename Fun>
auto unbind(Fun&& fun)
-> unbinder<Fun> {
return unbinder<Fun>(std::forward<Fun>(fun));
}
Since the function stored in the bind() expression will be passed by lvalue, you'll need a different declaration for your bar_cb(), however:
template<typename T>
void bar_cb(T& t) {
...
}
With that, you can register the bind()-expression using
f.bar(unbind(std::bind(lala)));
If you want to use f.bar(std::bind(lala)) you'll need a conditional definition of bar(): if it receives a bind()-expression it needs to automatically hide the fact that it is a bind()-expression by applying unbind() or something similar:
template<typename T>
typename std::enable_if<!std::is_bind_expression<typename std::decay<T>::type>::value>::type
bar(T&& t) {
std::cout << "bar (non-bind)\n";
doit(std::bind(&foo::template bar_cb<T>, this, std::forward<T>(t)));
}
template<typename T>
typename std::enable_if<std::is_bind_expression<typename std::decay<T>::type>::value>::type
bar(T&& t) {
std::cout << "bar (bind)\n";
doit(std::bind(&foo::template bar_cb<unbinder<T>>, this, unbind(std::forward<T>(t))));
}

Template function overload for base class [duplicate]

This question already has answers here:
Priority when choosing overloaded template functions in C++
(6 answers)
Closed 3 years ago.
How do I force compiler to pick up a template function overload for a base class?
Here is an example that illustrates the question
#include <iostream>
class A
{};
class B : public A
{};
template <class T>
void f (const T& t)
{
std::cout << "Generic f" << std::endl;
}
void f (const A& a)
{
std::cout << "Overload for A" << std::endl;
}
template <class T>
void call_f (const T& t)
{
f (t);
}
int main()
{
call_f (10);
call_f (A());
call_f (B());
return 0;
}
It produces the output
Generic f
Overload for A
Generic f
Why doesn't the compiler pick up f (const A&) in the 3rd case? UPD: OK, this one is clear void f<B> (const B&) is better than void f (const A&), but I'm still looking for answer to the 2nd question.
And is it possible to force it to do so without casting B to A?
Using call_f(B()) results in a call to `f() which is best matched by the template version. For the non-template version a conversion is required. As a result, the template is chosen. If the template and the non-template would be equally good options, the non-template would be preferred.
If you want to the non-template to be called, you'll need to make the template a non-option. for example, the template could be implemented like
#include <type_traits>
template <class T>
typename std::enable_if<!std::is_base_of<A, T>::value>::type f(T const&)
{
std::cout << "Generic f\n";
}
If C++11 can't be used you could either implement a version of std::is_base_of<...>, use a version from Boost or use a simple dispatch:
struct true_type {};
struct false_type {};
true_type A_is_base_of(A const*) { return true_type(); }
false_type A_is_base_of(void const*) { return false_type(); }
template <class T>
void f (T const&, false_type)
{
std::cout << "Generic f\n";
}
void f (A const&, true_type)
{
std::cout << "Overload for A\n";
}
template <class T>
void call_f (const T& t)
{
f (t, A_is_base_of(&t));
}
I think this actually is possible. The trick is to make use of the fact that overload resolution prefers pretty much anything to a C-style variadic function argument. That way we can create helper functions that support tagged dispatch by constructing the appropriate tag for us. Overload resolution of the helper function forces the compiler to remove the generic template function from its list of candidate functions, leaving only the specialized function.
This is a lot more clear with code, so let's take a look.
#include <iostream>
struct foo {};
struct bar : public foo {};
struct generic_tag {};
struct foo_tag {};
generic_tag make_tag(...) {
return generic_tag();
}
foo_tag make_tag(foo const *) {
return foo_tag();
}
template<typename T>
void f(T const &t, generic_tag) {
std::cout << "Generic" << std::endl;
}
void f(foo const &f, foo_tag) {
std::cout << "Specialized" << std::endl;
}
template<typename T>
void call_f(T const &t) {
// This is the secret sauce. The call to make_tag(t) will always
// select the most specialized overload of make_tag() available.
// The generic make_tag() will only be called if the compiler can't
// find some other valid version of make_tag().
f(t, make_tag(&t));
}
int main() {
call_f( 10); // Prints "Generic"
call_f(foo()); // Prints "Specialized"
call_f(bar()); // Prints "Specialized"
}
I verified this solution works on Ununtu 14.04 using GCC 4.8.2.
Assuming that you know that what you are calling call_f on will always be a derived type of A, you can simply explicitly ask for that version of the template, like so:
call_f<A> (B());
If you actually call it with a type that is not convertible to A, like a third class
class C
{};
You should get a compiler error addressing this problem (along the lines of "error C2664: 'call_f' : cannot convert parameter 1 from 'C' to 'const A &")