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?
Related
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.
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 have a template class that defines some member types. It's similar to how std::map defines it's value_type based on it's own template arguments, but in my case the type is more complex, so it's defined as nested class.
Now for debugging I would like to define operator<< for that type. But the compiler tells me it can't deduce the template parameters of the outer template.
My real code is not contrived like the following example, but this contrived example demonstrates the approach I tried and how it fails:
#include <iostream>
template <typename Value> class Outer;
template <typename Value>
std::ostream &operator<<(std::ostream &, const typename Outer<Value>::Inner &);
template <typename Value>
class Outer {
public:
struct Inner {
Value x;
};
void PrintSomething(Value v) {
// the real program does something useful with the inner class, of course
Inner inner = { v };
std::cout << "Inner = " << inner << std::endl; // <---- THIS SAYS IT CAN'T FIND operator<<
};
};
template <typename Value>
std::ostream &operator<<(std::ostream &s, const typename Outer<Value>::Inner &v) {
return s << v.x;
}
int main() {
Outer<int> o;
o.PrintSomething(42);
return 0;
}
This is complete sample to reproduce the problem. The compiler (I've tried 3 of them) says there is no overload of operator<< that would take second argument of type Outer<int>::Inner. When I try the same thing with different function that does not have other overloads, it instead says C2783: could not deduce template argument for 'identifier', gcc and clang keep saying there is no overload that takes second argument Outer<int>::Inner).
So is there a way to define operator<< taking Outer<Value>::Inner for any Value as it's right (so it can't be defined as member) argument?
Note: I need it to compile in several compilers and some of them don't have any C++11 features, so I need it to be C++03.
What you have there is a so-called non-deducible context. How could Value ever be deduced? You can partially specialize class templates, making it practically impossible for the compiler to even try and test every possible instantiation (of which there are.. well, infinite).
There are two workarounds: Take Inner out of Outer, or make operator<< an inline friend. The latter is the usual way people go.
template<class T>
struct Outer{
struct Inner{
T value;
friend std::ostream& operator<<(std::ostream& os, Inner const& v){
return os << v.value:
}
};
// ...
};
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.
Visual Studio compiles this code fine, but gcc only lets it compile without the Template operator. With the Template operator it gives the following errors:
Line 29: error: expected `;' before "itrValue"
class Test
{
public:
Test& operator<<(const char* s) {return *this;} // not implemented yet
Test& operator<<(size_t s) {return *this;} // not implemented yet
Test& operator<< (const std::list<const char*>& strList)
{
*this << "count=" << strList.size() << "(";
for (std::list<const char*>::const_iterator itrValue = strList.begin();
itrValue != strList.end(); ++itrValue)
{
*this << " " << *itrValue;
}
*this << ")";
return *this;
}
template <class T>
Test& operator<< (const std::list<T>& listTemplate)
{
*this << "count=" << listTemplate.size() << "(";
// this is line 28, the next line is the offending line
for (std::list<T>::const_iterator itrValue = listTemplate.begin();
itrValue != listTemplate.end(); ++itrValue)
{
*this << " " << *itrValue;
}
*this << ")";
return *this;
}
};
GCC is right, const_iterator is a type, and template dependant in the template operator<<, you need to tell the compiler it's a type and not a variable:
typename std::list<T>::const_iterator
To complete #Pieter answer, which is correct, some more info on how templates are processed.
First of all, templates are only compiled whenever they are instantiated, so that if you do not instantiate the template for a given type then the code will never be compiled.
Now, when you do instantiate a template, there is a two steps validation of the template code. First the template is verified for correctness regardless of what the instantiation type is. To check with a simpler to understand example:
#include "a.h"
template <typename T> void f( T const & )
{
T::type x; // is T::type a type?
};
int main()
{
A a;
f( a );
}
During the first phase, the template is checked for syntax correctness without considering what A really is. At this time the syntax A::type could be a type by the name of 'type' or it could be a static variable by the same name.
struct A { // version 1
typedef int type;
};
struct A { // version 2
static std::string type;
};
std::string A::type = "A";
In the first case, type is indeed a type, in the second it is not. Now the standard states that if it is really a type then the programmer of the template must state so to inform the compiler with the syntax above:
template <typename T> void f( T const & a )
{
typename T::type x; // define a variable x of type T::type
}
Now, to complete the processing, the compiler must check that the template code is not only correct in itself, but that when it is instantiated with the particular type T it is also correct. This is what the compiler performs during the second stage of validation. It applies the type and rechecks for errors.
In your case, it is a little more controversial, as everyone (but the compiler) knows that std::list::const_iterator is a type for any given T. Well, it does not need to be. From a language standpoint, some code could provide a template specialization for a particular data type T that is different to the general list template. The compiler cannot know whether that could be so.
Note that it would be horribly wrong to specialize a template in the std namespace with something that changes behavior in as much as redefining the iterator types. But the compiler sees std namespace just as any other namespace, and list as any other templated class.
I think it's worth telling you about the other disambiguations. For typename i already answered another one here.
The other one is template. Look here:
template<typename T>
struct some {
template<int V>
struct other {
typedef int type;
static const int value = V;
};
};
template<typename V>
void doit() {
typename some<V>::template other<42>::type * int_pointer;
}
Note how we had to use both template and typename disambiguations. The typename told the compiler
The thing you access called ::type is indeed a type. Don't do multiplication, which would wrongly assume ::type is a static value (integer or something).
The template told the compiler
The other<42> is a template used with the 42 argument. It's not a comparison using operator> and operator< of other with 42 and what follows (which would indeed be total nonsense).