C++: overloading does not choose expected method - c++

I have the following code:
#include <iostream>
#include <vector>
using namespace std;
struct A{};
struct B: public A {};
template <typename T>
void foo(const T& obj) { cerr << "Generic case"<< endl;}
void foo(const A& a) {
cerr << "Specific case" << endl;
}
int main() {
vector<int> v;
foo(v);
B b;
foo(b);
A a;
foo(a);
}
Output is
Generic case
Generic case
Specific case
Why is it that foo(const A& a) is not being chosen for the B object ?
Curiously enough, if I removed the templated method and just have the following:
#include <iostream>
#include <vector>
struct A{};
struct B: public A {};
//template <typename T>
//void foo(const T& obj) { cerr << "Generic case"<< endl;}
void foo(const A& a) {
cerr << "Specific case" << endl;
}
int main() {
B b;
foo(b);
A a;
foo(a);
}
The code compiles and the output is:
Specific case
Specific case
Why is the presence of the templated method making such a difference?
Edit: How can I force the compiler to choose the free method for classes derived from A in the presence
of the templated method?

No conversion is necessary for the call to foo(const B&) which the template instantiation yields thus it is the better match.
When a function call is seen by the compiler, every base function template has to be instantiated and is included in the overload set along with every normal function. After that overload resolution is performed. There is also SFINAE, which allows an instantiation of a function template to lead to an error (such a function would not be added to the overload set). Of course, things aren't really that simple, but it should give the general picture.
Regarding your edit: There is only one method to call. What else could there be as output?

Yes, it is a bit surprising but inheritance and template don't mix so well when it come to overload resolution.
The thing is, when evaluating which overload should be selected, the compiler chooses the one that necessitates the least conversions (built-in to built-in, derived-to-base, calls to non-explicit constructors or conversion operators, etc...). The ranking algorithm is actually pretty complex (not all conversions are treated the same...).
Once the overloads are ranked, if the two top-most are ranked the same and one is a template, then the template is discarded. However, if the template ranks higher than the non-template (less conversions, usually), then the template is selected.
In your case:
for std::vector<int> only one overload matches, so it is selected.
for A two overloads match, they rank equally, the template one is discarded.
for B two overloads match, the template rank higher (no derived-to-base conversion required), it is selected.
There are two work-arounds, the simplest is to "fix" the call site:
A const& ba = b;
foo(ba);
The other is to fix the template itself, however this is trickier...
You can hardcode that for classes derived from A this is not the overload you wish for:
template <typename T>
typename std::enable_if<not std::is_base_of<A, T>::value>::type
foo(T const& t) {
std::cerr << "Generic case\n";
}
However this is not so flexible...
Another solution is to define a hook. First we need some metaprogramming utility:
// Utility
template <typename T, typename Result = void>
struct enable: std::enable_if< std::is_same<T, std::true_type>::value > {};
template <typename T, typename Result = void>
struct disable: std::enable_if< not std::is_same<T, std::true_type>::value > {};
And then we define our hook and function:
std::false_type has_specific_foo(...);
template <typename T>
auto foo(T const& t) -> typename disable<decltype(has_specific_foo(t))>::type {
std::cerr << "Generic case\n";
}
And then for each base class we want a specific foo:
std::true_type has_specific_foo(A const&);
In action at ideone.
It is possible in C++03 too, but slightly more cumbersome. The idea is the same though, an ellipsis argument ... has the worst rank, so we can use overload selection on another function to drive the choice of the primary one.

#pmr's answer explains why the templated function is preferred in your example. To force the compiler to pick your overload instead, you can make use of SFINAE to drop the templated function from the overload set. Change the templated foo to
template <typename T>
typename std::enable_if<!std::is_base_of<A, T>::value>::type
foo(const T& obj) { cerr << "Generic case"<< endl;}
Now, if T is A or a class derived from A the templated function's return type is invalid and it will be excluded from overload resolution. enable_if is present in the type_traits header.

Related

How do I add a template specialization when for a generic method on a generic class when the two types are equal?

I'm trying to add in a specialization where the generic type of method and class agree, but I haven't been able to figure out exactly how to specify the template instantiation (if it is even possible).
My best guess would be something like the following (though it obviously doesn't compile):
template<typename ClassT>
class Foo
{
public:
ClassT x;
template<typename MethodT>
void Bar(MethodT arg)
{
}
};
template<typename T>
template<>
void Foo<T>::Bar(T arg)
{
x = arg;
}
As is usually the case when considering function template specialization, an overload can handle it:
template<typename MethodT>
void Bar(MethodT arg)
{
}
void Bar(ClassT arg)
{
x = arg;
}
When you call Bar, one of the candidates will be a function template specialization and one won't. Think of the class template as stamping out real, concrete member functions where possible when it's instantiated. There's a rule pretty late in overload resolution to prefer the one that isn't a function template specialization if it's a tie up to that point.
What you end up with is the second overload being called when there's an "exact match" in types (which allows for a difference in top-level const). If exact matches are too narrow, you can restrict the first overload to widen the second:
// Allow the other overload to win in cases like Foo<int>{}.Bar(0.0).
// std::enable_if works as well before C++20.
template<typename MethodT>
void Bar(MethodT arg) requires (not std::convertible_to<MethodT, ClassT>)
{
}
As discussed in the comments, it's not possible to do this with template specialization. However, something similar can be accomplished by using std::enable_if_t and
template<typename ClassT>
class Foo
{
public:
ClassT x;
template<typename MethodT,
typename = std::enable_if_t<!std::is_same<ClassT, MethodT>::value>>
void Bar(MethodT arg)
{
}
void Bar(ClassT arg)
{
x = arg;
}
};
std::enable_if_t will only return a valid type when the input type arg is true. Therefore, the template substitution will fail when MethodT and ClassT are the same type, but the non-template overload will not fail. The template substitution failure is ok under SFINAE.

How should ADL work for this?

Recently I came over an issue with clang++ 5.0.0 compiler where via ADL it was not picking up the correct function on Mac (but g++ did it correctly on Linux). I would like to know whether its a compiler issue OR poor class design in general.
Here is an example code (purely for illustration purpose):
namespace test {
class Ops {
public:
Ops():val_(0){}
template<typename T>
Ops& operator<< (const T& val) {
std::cout << "Called member function" << std::endl;
this->val_ = val;
return *this;
}
private:
int val_;
};
template<typename T>
struct Any {
T val_;
};
template <template<typename> class E, typename T>
Ops& operator<< (Ops& op, const E<T>& val) {
std::cout << "Global function" << std::endl;
return op;
}
}
int main() {
test::Ops op;
int k = 9;
test::Any<int> a;
op << a;
return 0;
}
I would like to know how ADL and template argument deduction wouldwork in step wise manner to find the best match ?
Would there be any situation for the same 'main body' the member function would be preferred in place of the free function ? (This is what is happening in the product build)
Thanks in advance.
This is what happens in detail and what every compiler should do: a candidate template function is found by qualified lookup
template <typename T>
test::Ops::operator<<(const T&)
while the second candidate is generated via ADL using template argument deduction (cfr. temp.deduct.conv)
template <template <typename> class E, typename T>
test::operator<<(test::Ops&, const E<T>&)
Afterwards overload resolution kicks in (cfr. 13.3.3) and the non-member one (F1) is preferred to the member (F2) one since
F1 and F2 are function template specializations, and the function template for F1 is more specialized
than the template for F2 according to the partial ordering rules described in 14.5.6.2.
and thus selected as the function to be called.
To answer your question: it depends on the overload resolution rules. Being a member function or in an inner scope doesn't affect the result and something like
namespace test {
class Ops {
public:
Ops():val_(0){}
template<typename T>
Ops& operator<< (const T& val) {
std::cout << "Called member function" << std::endl;
this->val_ = val;
return *this;
}
private:
int val_;
};
template<typename T>
struct Any {
T val_;
};
template <typename E>
Ops& operator<< (Ops& op, const E& val) {
std::cout << "Global function" << std::endl;
return op;
}
}
would just trigger an overload resolution error 'use of overloaded operator '<<' is ambiguous'.
As a plus: the member function is wrong even if it were chosen: this->val is assigned a non-integer type.
These two candidate functions are in the overload set:
// member function template, found by qualified lookup
template <typename T>
test::Ops::operator<<(const T&)
// non-member function template, found by ADL
template <template <typename> class E, typename T>
test::operator<<(test::Ops&, const E<T>&)
In operator lookup, no preference is given to members versus non-members. After template argument substitution, both function template specializations exactly match (with qualification conversions) the supplied argument types. But the function taking E<T> is more specialized than the one taking T, so the non-member function is chosen for this reason.
Apple clang 5.0.0 is based on LLVM clang 3.3svn. I can't find any version of LLVM clang which selects the member function. It could be a bug in Apple's code, but IMHO it's more likely to be some subtle difference in the code you are actually compiling or your environment. Have you tried compiling your example code with the suspect compiler?

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;

Call function template overload for derived variadic class template

I have a variadic class template deriv which derives off variadic class template base.
I have a function template which takes any type T, and an overload for base<Ts...> types;
How can I get the base<Ts...> overload to be used when passing a const deriv<Ts...>&?
Working example below:
#include <iostream>
#include <tuple>
template<typename... Ts>
struct base
{
std::tuple<Ts...> tuple;
};
template<typename... Ts>
struct deriv : base<Ts...>
{
};
//--------------------------------
template<typename T>
void func(const T&)
{
std::cout << "T" << std::endl;
}
template<typename... Ts>
void func(const base<Ts...>&)
{
std::cout << "base<Ts...>" << std::endl;
}
//----------------------------------------
int main()
{
int a;
base <int, double> b;
deriv<int, double> c;
func(a);
func(b);
func(c); // <--- I want func<base<Ts...>> not func<T> to be called here
exit(0);
}
Output from exemplar:
T
base<Ts...>
T
What I want the output to be:
T
base<Ts...>
base<Ts...>
Unless you are ready to re-engineer your code, you cannot, and for a good reason.
Your non-variadic overload of func() is a better match than the variadic version: in fact, when attempting to resolve your function call, the type parameter T for the non-variadic overload will be deduced to be derived<int, double>.
On the other hand, the parameter pack Ts in your variadic overload will be deduced to be int, double. After type deduction, this will practically leave the compiler with these two choices for resolving your call:
void func(const deriv<int, double>&); // Non-variadic after type deduction
void func(const base<int, double>&); // Variadic after type deduction
Which one should be picked when trying to match a call whose argument is of type derived<int, double>?
deriv<int, double> c;
func(c);
Obviously, the first, non variadic overload is a better match.
So how do you get the second overload called instead of the first? You have a few choices. First of all, you can qualify your call by explicitly specifying the template arguments:
func<int, double>(c);
If you do not like that, maybe you can re-think the definition of the non-variadic overload of func(): do you really want it to accept any possible type T? Or are there some types for which you know this overload is not to be invoked? If so, you can use SFINAE techniques and std::enable_if to rule out the undesired matches.
As a further possibility, you can relax a bit the signature of your template function and allow deducing its argument as an instantiation of a certain template class:
template<template<typename...> class T, typename... Ts>
void func(const T<Ts...>&)
{
std::cout << "base<Ts...>" << std::endl;
}
This change alone should fix your program's behavior in the way you want.
UPDATE:
If you want your specialized function template to be invoked only for classes derived from any instance of the base<> class template, you can use the std::is_base_of<> type trait and std::enable_if in the following way:
template<template<typename...> class T, typename... Ts>
void func(
const T<Ts...>&,
typename std::enable_if<
std::is_base_of<base<Ts...>, T<Ts...>>::value
>::type* = nullptr
)
{
std::cout << "base<Ts...>" << std::endl;
}
ADDENDUM:
In those situations where template function overloading won't help with your design, notice that you can always resort to partial template specialization. Unfortunately, function templates cannot be specialized, but you can still exploit class template partial specialization and add a helper function to hide the instantiation of that template. This is how you would rewrite your code:
namespace detail
{
template<typename T>
struct X
{
static void func(const T&)
{
std::cout << "T" << std::endl;
}
};
template<template<typename...> class T, typename... Ts>
struct X<T<Ts...>>
{
static void func(const T<Ts...>&)
{
std::cout << "base<Ts...>" << std::endl;
}
};
}
template<typename T>
void func(const T& t)
{
details::X<T>::func(t);
}
The generic-template overload is a better match, since it requires no conversion (except adding const, which both overloads have).
You can get the base-template overload by adding an explicit cast (example):
func(static_cast<base<int, double> &>(c));
(Alternatively, you could forgo the multiple overloads and instead stick some is_base_of helper logic into your main function template's body.)

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?