understanding operator lookup; which compiler is correct? - c++

This may be asked before but I didn't have luck finding an answer...
I have an unordered container (i.e. a hash; we'll call it QHash, because it is, though this probably happens in any similar situation) that needs a comparison operator for it's key type.
Consider the following:
// foo.h
class Bar
{
public:
class Foo {};
};
// foo.cpp
#include <QtCore/QHash>
namespace
{
typedef Bar::Foo Foo;
bool operator==(Foo const& a, Foo const& b) { return &a == &b; }
}
uint qHash(Foo const& foo) { return qHash(&foo); }
int main()
{
QHash<Foo, int> hash;
// do stuff with hash, e.g.:
hash.insert(Foo(), 5);
return 0;
}
Using G++, all is well. However, clang gives an error in the bowels of qhash.h about invalid operands to binary expression where trying to use == on instances of Foo. It seems to me that clang is either not finding or rejecting the definition of operator== in the anonymous namespace, probably due to different lookup rules than G++.
I am wondering, which compiler is correct?
p.s. I'm building in C++11 mode, in case it makes a difference.

Well, ADL looks into the namespaces a class is defined in. Look
at
[basic.lookup.argdep]/2:
"For each argument type T in the function call, there is a set of zero
or more associated namespaces and a
set of zero or more associated classes to be considered. The sets of
namespaces and classes is determined
entirely by the types of the function arguments (and the namespace of
any template template argument).
Typedef names and using-declarations used to specify the types do not
contribute to this set."
Note the last sentence.
So, for the original example, the typedef in the namespace of the
operator doesn't help,
gcc is wrong and clang is right.

This is a known GCC bug. Essentially, the problem is that GCC does not correctly implement two-phase name lookup for operator names. Your operator== is not found by unqualified lookup (because it is declared too late) and is not found by argument-dependent name lookup (because ::(anonymous namespace) is not an associated namespace of Bar::Foo, so should not be considered inside the instantiation of qHash.
If you move the definition of qHash into the anonymous namespace, GCC will then reject the code, because its bug only applies to operator names and not to normal function names.

Despite your claim that the choice of unordered container doesn't matter, the following self-contained fully standard code generates consistent errors on both g++ and clang -- neither one finds operator==.
#include <unordered_map>
// foo.h
class Bar
{
public:
class Foo {};
};
// foo.cpp
namespace
{
typedef Bar::Foo Foo;
bool operator==(Foo const& a, Foo const& b) { return &a == &b; }
}
namespace std
{
template <>
struct hash<Foo>
{
std::size_t operator()(const Foo& k) const
{
return std::hash<const Foo*>()(&k);
}
};
}
int main()
{
std::unordered_map<Foo, int> hash;
// do stuff with hash, e.g.:
hash.emplace(Foo(), 5);
return 0;
}
The important part of the error is
error: no match for operator== (operand types are const Bar::Foo and const Bar::Foo)
{ return __x == __y; }
Basically, if you want operators to be found by library code, stick them in an associated namespace of the class and let ADL do its thing. Definitely don't use an anonymous namespace, unless the class itself is inside the anonymous namespace.

Related

Operator overloading, name resolution and namespaces

I would like some light to be shed on a puzzling situation involving ADL, namespaces and operator overloading.
Let Foo be a library which defines a class ( Deriv) in its own namespace, along with a templated operator * which returns another class.
namespace Foo {
class Deriv {};
class Another {};
template <typename T>
Another operator* ( T x, const Deriv& d ) { return Another();}
}
Now I use Foo's class in my own library Bar, which defines another operator *, this time only for float.
namespace Bar {
typedef Foo::Deriv MyDeriv;
MyDeriv operator* (float x, const MyDeriv& d) { return MyDeriv();}
}
I observe a difference in compiler behaviour depending whether one is inside namespace Bar or not.
This function (Bar::f1) compiles, using the second version of the operator * :
namespace Bar {
void f1() {
Bar::MyDeriv a;
Bar::MyDeriv b = 3.f * a;
}
}
while the same function outside namespace Bar (f2()) fails to compile, because the compiler attempts only to use Foo::operator* and cannot guess that it must use Bar::operator*.
void f2() {
Bar::MyDeriv a;
Bar::MyDeriv b = 3.f * a; // Error : cannot convert Foo:Another to Bar::Myderiv
}
You can see the code live here :http://ideone.com/pkPeOY
Now, if Foo::operator* was not templated and defined as Foo::operator*(float, const Deriv& d); then both functions fail to compile with the same error (ambiguous operator overload), as can be seen here : http://ideone.com/wi1EWS
So, facing this situation, this is what is puzzling me
In the templated case, when compiling f2, the compiler considers using Foo::operator* but not Bar::operator*, while in the non-templated case, it considers using both (and refuses to go further because of the ambiguity). What makes the compiler behave differently ?
A user of my library Bar will be outside the Bar:: namespace, yet I want Bar::operator* to be used, and not Foo::operator*. I considered explicitely calling Bar::operator*(3.f,a), which is ugly, or inserting my own operator in the global namespace, which I reckon is a Bad Thing. Is there an option I am missing, or am I doing something wrong ?
In the templated case, when compiling f2, the compiler considers using Foo::operator* but not Bar::operator*, while in the non-templated case, it considers using both (and refuses to go further because of the ambiguity). What makes the compiler behave differently ?
In both cases the compiler considers using both, but in the case of a templated operator*, the call is not ambiguous since there is a non-templated function which parameter types perfectly matches the arguments (try replace 3.f with 3. and you will see that the templated version is found). Typically:
template <typename T>
void g (T) { }
void g (float) { }
g(0.f); // Ok, the overload for float is preferred over the templated version
A user of my library Bar will be outside the Bar:: namespace, yet I want Bar::operator* to be used, and not Foo::operator*. I considered explicitely calling Bar::operator*(3.f,a), which is ugly, or inserting my own operator in the global namespace, which I reckon is a Bad Thing. Is there an option I am missing, or am I doing something wrong ?
Unfortunately, ADL will not find your overload since the only parameters of operator* are float and MyDeriv which are defined inside the namespace Foo. One possible way would be to inherit from Foo::Deriv:
namespace Bar {
struct MyDeriv: public Foo::Deriv {};
MyDeriv operator* (float x, const MyDeriv& d) { return MyDeriv();}
}
Another one is to declare your overload for operator* inside the Foo namespace:
namespace Bar {
typedef Foo::Deriv MyDeriv;
}
namespace Foo {
Bar::MyDeriv operator* (float x, const Bar::MyDeriv& d) { return Bar::MyDeriv(); }
}

Providing swap() for a C++ template class breaks std::swap()?

I was trying to implement the copy-and-swap idiom in my custom Matrix class, and I ran into some trouble with the implementation of swap() in the way suggested in the linked-to question:
(The compiler I used is the one from MS VS2010 IDE, dialect is good old-fashioned C++03.)
// matrix.h
namespace my_space
{
template<typename T> class Matrix
{
public:
/* ... */
friend void swap(Matrix<T> &first, Matrix<T> &second)
{
using std::swap;
swap(first.width_, second.width_);
swap(first.height_, second.height_);
swap(first.data_, second.data_);
}
};
} // namespace
Now I have trouble reaching regular std::swap() in the code for functions residing in this namespace:
// some_code.cpp:
#include "matrix.h"
#include <algorithm>
using namespace my_space;
using namespace std;
// SomeClass is part of my_space!
void SomeClass::some_function()
{
int a = 3, b = 7;
swap(a,b); // I wan't std::swap!
}
Unfortunately, for some reason, my_space::swap() for Matrix seems to alias all other calls to std::swap(), and I've no idea why since the arguments don't fit and ADL should favor std::swap:
1>f:\src\some_code.cpp(653): error C3767: 'swap': candidate function(s) not accessible
1> could be the friend function at 'f:\src\matrix.h(63)' : 'swap' [may be found via argument-dependent lookup]
(The error repeats 10 times for every line where I'm trying to use std::swap)
Does my_space::swap() always overrule std::swap() in my_space, even if the arguments don't fit? It's not as if std::swap() is not visible, and it worked OK before my_space::swap() was created.
The approach taken by STL containers uses a member function and then overload the static function. For example:
template<class T, class Alloc=std::allocator<T> >
class vector
{
T *data;
size_t n;
size_t max_n;
public:
void swap(vector<T, Alloc> &other)
{
swap(this->data, other.data);
swap(this->n, other.n);
swap(this->max_n, other.max_n);
}
};
template<class T, class A>
void swap(vector<T, A> &lhs, vector<T, A> &rhs)
{
lhs.swap(rhs);
}
In the suggested Matrix class, simply take the same approach...
namespace my_space
{
template<typename T>
class Matrix
{
unsigned width_;
unsigned height_;
std::vector<T> data_;
public:
void swap(Matrix<T> &other)
{
std::swap(this->width_, other.width_);
std::swap(this->height_, other.height_);
std::swap(this->data_, other.data_); // calls this->data_.swap(other.data_);
}
};
}
namespace std
{
template<typename T>
void swap(my_space::Matrix<T> &lhs, my_space::Matrix<T> &rhs)
{
lhs.swap(rhs);
}
}
Include the following line in Matrix:
template<typename U> friend void swap(Matrix<U> &first, Matrix<U> &second);
and define the swap outside of the class. The reason you are getting the error function template has already been defined, is because each instantiation of Matrix<unsigned short> and Matrix<char> will contain the same defintion of your swap function since you defined the friend function inside of the Matrix template.
The following builds cleanly for me with VC++ 2010 SP1:
Matrix.h:
#pragma once
#include <algorithm>
#include <vector>
namespace my_space
{
template<typename T>
class Matrix
{
public:
Matrix(unsigned const w, unsigned const h)
: width_(w), height_(h), data_(w * h)
{ }
private:
unsigned width_;
unsigned height_;
std::vector<T> data_;
friend void swap(Matrix& lhs, Matrix& rhs)
{
using std::swap;
swap(lhs.width_, rhs.width_);
swap(lhs.height_, rhs.height_);
swap(lhs.data_, rhs.data_);
}
};
}
.cpp:
#include "Matrix.h"
int main()
{
using namespace my_space;
using std::swap;
int a(0), b(1);
swap(a, b);
Matrix<int> c(2, 3), d(4, 5);
swap(c, d);
Matrix<short> e(6, 7), f(8, 9);
swap(e, f);
}
Since you didn't post an SSCCE (hint, hint), it's very difficult to see exactly where you're going wrong, but you can use this as a starting point to narrow down your issue.
If the code is really like what you posted, that is an issue with the compiler. The code compiles fine in clang++, as it should.
Friend declarations are strange in that they declare a function that has namespace scope, but the declaration is only available though ADL, and even then, only if at least one of the arguments is of the type of the class that has the friend declaration. Unless there is a namespace level declaration, the function is not available in the namespace scope.
Test 1
(function not available at namespace level with out an explicit declaration):
namespace A {
struct B {
friend void f(); // [1]
};
// void f(); // [2]
}
void A::f() {} // [3]
In [1] we add a friend declaration, that declares void A::f() as a friend of A::B. Without the additional declaration in [2] at namespace level, the definition in [3] will fail to compile, since being outside of the A namespace that definition is not also a self-declaration.
The implication here is that, because the function is not available for lookup at namespace level, but only through ADL on Matrix<T> (for some particular instantiating type T), the compiler cannot possibly find that as a match to a swap of two int values.
In his answer, Jesse Good states that each instantiation of Matrix and Matrix will contain the same defintion of your swap function since you defined the friend function inside of the Matrix template which is completely absurd.
A friend function that is defined inside the class will declare and define a namespace level function, and again, the declaration will only be available inside the class and accessible through ADL. When this is done inside a template it will define a non-templated free function at namespace level for each instantiation of the template that uses the function. That is, it will generate different definitions. Note that inside the class template scope, the name of the template identifies the specialization that is being instantiated, that is, inside Matrix<T>, the identifier Matrix does not name the template, but one instantiation of the template.
Test 2
namespace X {
template <typename T>
struct A {
friend void function( A ) {}
};
template <typename T>
void funcTion( A<T> ) {}
}
int main() {
using namespace X;
A<int> ai; function(ai); funcTion(ai);
A<double> ad; function(ad); funcTion(ad);
}
$ make test.cpp
$ nm test | grep func | c++filt
0000000100000e90 T void X::funcTion<double>(A<double>)
0000000100000e80 T void X::funcTion<int>(A<int>)
0000000100000e70 T X::function(A<double>)
0000000100000e60 T X::function(A<int>)
The output of nm is the list of symbols, and c++filt will translate the mangled names into the equivalent in C++ syntax. The output of the program clearly shows that X::funcTion is a template that has been instantiated for two types, while X::function are two overloaded non-templated functions. Again: two non-templated functions.
Claiming that it would generate the same function makes little sense, consider that it had a function call, say std::cout << lhs, the code must pick the correct overload of operator<< for the current instantiation of the function. There is no single operator<< that can take say a int and an unsigned long or std::vector<double> (Nothing inhibits you from instantiating the template with any type.
The answer by ildjarn proposes an alternative, but provides no explanation of the behavior. The alternative works because a using-directive is completely different from a using-declaration. In particular, the former (using namespace X;) modifies lookup so that the identifiers in namespace X are available at namespace level in one of the enclosing namespaces of the current piece of code (if you build a tree of namespaces, the declarations would be available where the branch containing X meets the branch containing the code where the using-directive is used).
On the other hand, a using-declaration (using std::swap;) provides a declaration of the function std::swap in the context where the using-declaration is present. This is why you must use using-declarations and not using-directives to implement your swap functions:
Test 3
namespace Y { struct Z {}; void swap( Z&,Z& ); }
namespace X {
struct A { int a; Y::Z b; };
void swap( A& lhs, A& rhs ) {
//using namespace std; // [1]
using std::swap; // [2]
swap( lhs.a, rhs.a ); // [3]
swap( lhs.b, rhs.b ); // [4]
}
}
If we had used a using-directive [1], the symbols from the ::std namespace would be available for lookups performed inside the function ::X::swap(X::A&,X::A&) as if they had been declared in :: (which is the common ancestor of ::std and ::X). Now the swap in [3] will not find any swap function through ADL, so it will start searching for swap functions in the enclosing namespace. The first enclosing namespace is X, and it does contain a swap function, so lookup will stop and overload resolution will kick in, but X::swap is not a valid overload for swap(int&,int&), so it will fail to compile.
By using a using-declaration we bring std::swap declaration to the scope of X::swap (inside the function!). Again, ADL will not be applied in [3], and lookup will start. In the current scope (inside the function) it will find the declaration of std::swap and will instantiate the template. In [4], ADL does kick in, and it will search for a swap function defined inside the ::Y::Z function and/or in ::Y, and add that to the set of overloads found in the current scope (again, ::std::swap). At this point, ::Z::swap is a better match than std::swap (given a perfect match, a non-templated function is a better match than a templated one) and you get the expected behavior.

My explicit instantiation of template class seems doesn't work

I wrote a short program to test the template class's explicit instantiation as follows:
#include <iostream>
template <class T>
struct less_than_comparable {
friend bool operator>=(T const& a, T const& b) {
return !(a < b);
}
};
class Point {
friend bool operator<(Point const& a, Point const& b) {
return a.x_ < b.x_;
}
public:
Point(int x) : x_(x) {}
private:
int x_;
};
template struct less_than_comparable<Point>;
//Here I explicitly instantiate a template class expecting that
//less_han_comparable<Point> would export opeartor>=() for class Point to the global
//namespace, and then the p1 >= p2 statement will work as expected.
int main() {
using namespace std;
Point p1(1), p2(2);
cout << (p1 < p2) << endl;
cout << (p1 >= p2) << endl; //But I have a compiler error here saying that
//no match for ‘operator>=’ in ‘p1 >= p2’
}
I know if I inherit Point from less_than_comparable, the code will pass the compiling.
But my question is why it doesn't work if I use explicit instantiation?
I use G++ 4.4.5 running on Ubuntu 10.04.
Any comments will be appreciated. Thanks.
The problem is that friend functions defined inside class-like types are not injected into enclosing namespace.
The principle you are refering to is called "friend name injection", but this has been replaced in current C++ standard by "ADL" (Argument Dependent Lookup, also called Koenig Lookup). ADL examines all namespaces associated with function parameter types for matching function.
In your case, when you call operator>= in p1 >= p2 (i.e. operator>=(p1, p2);). ADL looks for matching function in the namespace of Point, but Point doesn't have such function.
If you inherit Point from less_than_comparable, operator>= becomes part of namespace of Point and ADL can find it here.
You can check, that no friend name injection takes place here.
The code doesn't work because Point is not a template class where you have defined operator >=.
If you want to compile this code then define operator >= in Point class as well. Note that p1 and p2 are no where related to less_than_comparable.
As side note, why you have defined operator for "greater than equal to" operator in the name of less_than_comparable ?
Explicit instantiation is simply a way to force the compiler to compile a particular template within that translation unit - it has no affect on the lookup of names.
To get what you appear to want, you could for example:
class Point : public less_than_comparable<Point> {
your operator >= is a member function of a completely different type that is unrelated to Point as far as the compiler is concerned. I think what you want to do is:
template< T >
bool operator >= ( T const& a, T const& b ) {... }
forget the class and just make it a global function. And you won't need explicit template instantiation. In fact the only time I've seen it used was when you had template class declared inside a library and used in another project, which you are obviously not doing here.

In C++ template function, why does dependent function call give "not declared" error?

Inside a C++ template function foo(), a call to ::bar(TT*) gives the following error under gcc 4.4.3:
g++ -o hello.o -c -g hello.cpp
hello.cpp: In function 'void foo(std::vector<TT*, std::allocator<TT*> >&)':
hello.cpp:8: error: '::bar' has not been declared
Here's the offending code:
// hello.cpp
#include <vector>
template<typename TT> void foo(std::vector<TT*> &vec)
{
TT *tt;
::bar(tt);
vec.push_back(tt);
}
class Blah
{
};
void bar(Blah *&)
{
}
int main(int argc, char *argv[])
{
std::vector<Blah*> vec;
foo(vec);
return 0;
}
C++ distinguishes between symbols that are dependent on the template parameter (TT, here) and those symbols that are independent and can be evaluated immediately.
Clearly, the compiler thinks my ::bar(TT*) call is independent and tries to resolve it immediately. Just as clearly, that function call is dependent on TT because the function call takes a parameter of type TT*, so the compiler should wait until the foo(vec) instantiation to resolve ::bar(TT*).
Is this a gcc bug or am I missing something subtle about C++ templates?
EDIT: here's a slightly more complicated example with two versions of ::bar() to clarify that declaration order is not the issue with my problem. When parsing the template, the compiler has no way of knowing if main() down below is going to instantiate the template function with TT=Blah or with TT=Argh. Therefore the compiler should not be giving an error until line 35 line 28 at the earliest (if ever). But the error is given for line 8 line 16.
EDIT #2: improved this example.
EDIT #3: added corrections to this example to make it work as desired. The bar(tt) now correctly refers to bar(Blah*). Rationale given below. (Thanks everyone).
// hello.cpp
#include <vector>
class XX {};
void bar(XX*) {}
class CC {
public:
void bar();
void bar(int *);
void bar(float *);
template<typename TT> static void foo(std::vector<TT*> &vec);
};
template<typename TT>
void CC::foo(std::vector<TT*> &vec) {
using ::bar;
TT *tt;
bar(tt);
vec.push_back(tt);
}
class Argh {};
void bar(Argh *&aa) { aa = new Argh; }
class Blah {};
void bar(Blah *&bb) { bb = new Blah; }
int main(int argc, char *argv[]) {
std::vector<Blah*> vec;
CC::foo(vec);
return 0;
}
Nobody has yet pointed out any part of the current Standard that says I can't.
C++03 does not make the name ::bar dependent. Dependency happens for type names by dependent types, and for non-type names by dependent expressions that are either type or value dependent. If a name is looked up in a dependent type, it becomes a type-dependent id-expression (14.6.2.2/3 last bullet), and its lookup is delayed until instantiation. The name ::bar is no such dependent expression. If you were to call bar(tt), a special rule of C++03 at 14.2.6 says
In an expression of the form:
postfix-expression ( expression-listopt )
where the postfix-expression is an identifier, the identifier denotes a dependent name if and only if any of the expressions in the expression-list is a type-dependent expression (14.6.2.2).
So you need to remove the :: in order to make it an identifier and to make it dependent by this special rule.
The reason I can't remove the :: is that in my real code, the template function foo is a member function of class CC, and there exist a family of overloaded member functions CC::bar(...), meaning I need to qualify ::bar(TT*) to avoid defaulting to CC::bar(...). That's what :: exists for, I'm surprised if the Standard says I can't use :: here
The proper way to solve it is to introduce a using declaration into the local scope of your function.
namespace dummies { void f(); }
template<typename T>
struct S {
void f();
void g() {
using dummies::f; // without it, it won't work
f(T()); // with ::f, it won't work
}
};
struct A { };
void f(A) { } // <- will find this
int main() {
S<A> a;
a.g();
}
ADL will not do anything if ordinary lookup finds a class member function. Therefor, you introduce a using declaration, so ordinary lookup doesn't find a class member function, and ADL can advance the declarations visible when instantiating.
But this seems to disagree with you: Stroustrup TC++PL Sp Ed, Section C.13.8.1, Dependent Names: "Basically, the name of a function called is dependent if it is obviously dependent by looking at its arguments or at its formal parameters"
Stroustrup's book is also written for people who possibly don't know C++ yet. It won't try to cover all rules with 100% accuracy, as is normal for these books. The gory details are left for ISO Standard readers.
Also, the formal parameters of a function have nothing to do with whether a function call is dependent or not. In the IS, only actual arguments define dependency of a function name. This was different in an old draft from 1996, which had the notion of implicit and explicit dependency. Implicitly dependency was defined as
A name implicitly depends on a template-argument if it is a function
name used in a function call and the function call would have a dif-
ferent resolution or no resolution if a type, template, or enumerator
mentioned in the template-argument were missing from the program.
[...]
[Example: some calls that depend on a template-argument type T are:
The function called has a parameter that depends on T according to
the type deduction rules (temp.deduct). For example, f(T),
f(Array), and f(const T*).
The type of the actual argument depends on T. For example, f(T(1)),
f(t), f(g(t)), and f(&t) assuming that t has the type T.
A practical example is also given
This ill-formed template instantiation uses a function that does not
depend on a template-argument:
template<class T> class Z {
public:
void f() const
{
g(1); // g() not found in Z's context.
// Look again at point of instantiation
}
};
void g(int);
void h(const Z<Horse>& x)
{
x.f(); // error: g(int) called by g(1) does not depend
// on template-argument ``Horse''
}
The call x.f() gives rise to the specialization:
void Z<Horse>::f() { g(1); }
The call g(1) would call g(int), but since that call does not depend
on the template-argument Horse and because g(int) was not in scope at
the point of the definition of the template, the call x.f() is ill-
formed.
On the other hand:
void h(const Z<int>& y)
{
y.f(); // fine: g(int) called by g(1) depends
// on template-argument ``int''
}
Here, the call y.f() gives rise to the specialization:
void Z<int>::f() { g(1); }
The call g(1) calls g(int), and since that call depends on the tem-
plate-argument int, the call y.f() is acceptable even though g(int)
wasn't in scope at the point of the template definition. ]
These things are left to history, and even the last traces from it are disappearing slowly, albeit not actively driven (n3126 for instance gets rid of "explicitly depends" at [temp.names]/p4 as a side-effect of another change, because the distinction between "explicitly depends" and "implicitly depends" has never existed in the IS).
From section 14.7.2 of the C++ spec:
In an expression of the form:
postfix-expression ( expression-listopt )
where the postfix-expression is an unqualified-id but not a template-id , the unqualified-id denotes a dependent
name if and only if any of the expressions in the expression-list is a type-dependent expression (14.7.2.2).
since ::b is not an unqualified id, it is not a dependent name. If you remove the ::, it is an unqualified name and so is a dependent name. For a non-dependent name, the lookup occurs at the point of the template declaration, not the instantiation, and at that point there is no global declaration of bar visible, so you get an error.
This ugliness works with Intel C++ 11.0 and perhaps illuminates the compiler's point of view:
#include <vector>
#include <iostream>
// *********************
// forward declare in the global namespace a family of functions named bar
// taking some argument whose type is still a matter of speculation
// at this point
template<class T>
void bar(T x);
// *********************
template<typename TT>
void foo(std::vector<TT*> &vec)
{
TT *tt;
::bar(tt);
vec.push_back(tt);
}
class Blah
{
public:
};
void bar(Blah *x)
{
// I like output in my examples so I added this
std::cout << "Yoo hoo!" << std::endl;
}
// **********************
// Specialize bar<Blah*>
template<>
inline
void bar<Blah*>(Blah *x) { ::bar(x); }
// **********************
int main(int, char *)
{
std::vector<Blah*> vec;
foo(vec);
return 0;
}
This should work, your problem is the declaration order:
// hello.cpp
#include <vector>
class Blah
{
public:
};
void bar(Blah *&)
{ }
template<typename TT> void foo(std::vector<TT*> &vec)
{
TT *tt;
::bar(tt);
vec.push_back(tt);
}
int main(int argc, char *argv[])
{
std::vector<Blah*> vec;
foo(vec);
return 0;
}
A dependent name still requires a function declaration. Any function declaration with that name will do, but there must be something. How else would the compiler disambiguate an overloaded function call from, say, a misspelled functor object? In other words, finding some function of that name, thus verifying that overloading on that name is possible, instigates the overload resolution process in qualified (or unqualified) name lookup.
// hello.cpp
#include <vector>
void bar(); // Comeau bails without this.
template<typename TT> void foo(std::vector<TT*> &vec)
{
TT *tt;
::bar(tt);
vec.push_back(tt);
}
class Blah
{
};
void bar(Blah *&)
{
}
int main(int argc, char *argv[])
{
std::vector<Blah*> vec;
//foo(vec); - instanting it is certainly an error!
return 0;
}
Your code works fine on VS2005. so it indeed seems like a bug in gcc. (I don't know what the specs say about this, maybe someone will come along and post it.)
As for gcc, I also tried defining a different overload of bar before foo, so that the symbol bar is at least defined:
void bar(float *) {
}
template<typename TT> void foo(std::vector<TT*> &vec)
{
TT *tt;
::bar(tt);
vec.push_back(tt);
}
void bar(int *) {
}
int main(int argc, char *argv[])
{
std::vector<int*> vec;
foo(vec);
return 0;
}
but gcc is still totally blind to the int * overload:
error: cannot convert int* to float* for argument 1 to void bar(float*)
It seems gcc will only use those functions that are defined before the template itself.
However, if you remove the explicit :: specifier and make it just bar(tt), it seems to work fine. Chris Dodd's answer seems satisfactory in explaining why this is so.

Why is std::function not equality comparable?

This question also applies to boost::function and std::tr1::function.
std::function is not equality comparable:
#include <functional>
void foo() { }
int main() {
std::function<void()> f(foo), g(foo);
bool are_equal(f == g); // Error: f and g are not equality comparable
}
In C++11, the operator== and operator!= overloads just don't exist. In an early C++11 draft, the overloads were declared as deleted with the comment (N3092 §20.8.14.2):
// deleted overloads close possible hole in the type system
It does not say what the "possible hole in the type system" is. In TR1 and Boost, the overloads are declared but not defined. The TR1 specification comments (N1836 §3.7.2.6):
These member functions shall be left undefined.
[Note: the boolean-like conversion opens a loophole whereby two function instances can be compared via == or !=. These undefined void operators close the loophole and ensure a compile-time error. —end note]
My understanding of the "loophole" is that if we have a bool conversion function, that conversion may be used in equality comparisons (and in other circumstances):
struct S {
operator bool() { return false; }
};
int main() {
S a, b;
bool are_equal(a == b); // Uses operator bool on a and b! Oh no!
}
I was under the impression that the safe-bool idiom in C++03 and the use of an explicit conversion function in C++11 was used to avoid this "loophole." Boost and TR1 both use the safe-bool idiom in function and C++11 makes the bool conversion function explicit.
As an example of a class that has both, std::shared_ptr both has an explicit bool conversion function and is equality comparable.
Why is std::function not equality comparable? What is the "possible hole in the type system?" How is it different from std::shared_ptr?
Why is std::function not equality comparable?
std::function is a wrapper for arbitrary callable types, so in order to implement equality comparison at all, you'd have to require that all callable types be equality-comparible, placing a burden on anyone implementing a function object. Even then, you'd get a narrow concept of equality, as equivalent functions would compare unequal if (for example) they were constructed by binding arguments in a different order. I believe it's impossible to test for equivalence in the general case.
What is the "possible hole in the type system?"
I would guess this means it's easier to delete the operators, and know for certain that using them will never give valid code, than to prove there's no possibility of unwanted implicit conversions occurring in some previously undiscovered corner case.
How is it different from std::shared_ptr?
std::shared_ptr has well-defined equality semantics; two pointers are equal if and only if they are either both empty, or both non-empty and pointing to the same object.
I may be wrong, but I think that equality of std::function objects is unfortunately not solvable in the generic sense. For example:
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <cstdio>
void f() {
printf("hello\n");
}
int main() {
boost::function<void()> f1 = f;
boost::function<void()> f2 = boost::bind(f);
f1();
f2();
}
are f1 and f2 equal? What if I add an arbitrary number of function objects which simply wrap each other in various ways which eventually boils down to a call to f... still equal?
Why is std::function not equality comparable?
I think main reason is that if it were, then it couldn't be used with non equality comparable types, even if equality comparison is never performed.
I.e. code that performs comparison should be instantiated early - at the time when a callable object is stored into std::function, for instance in one of the constructors or assignment operators.
Such a limitation would greatly narrow the scope of application, and obviously not be acceptable for a "general-purpose polymorphic function wrapper".
It is important to note that it is possible to compare a boost::function with a callable object (but not with another boost::function)
Function object wrappers can be compared via == or != against any function object that can be stored within the wrapper.
This is possible, because function that performs such comparison is instantiated at point of comparison, based on known operand types.
Moreover, std::function has a target template member function, which can be used to perform similar comparison. In fact boost::function's comparison operators are implemented in terms of target member function.
So, there are no technical barriers which block implementation of function_comparable.
Among answers there is common "impossible in general" pattern:
Even then, you'd get a narrow concept of equality, as equivalent functions would compare unequal if (for example) they were constructed by binding arguments in a different order. I believe it's impossible to test for equivalence in the general case.
I may be wrong, but I think that equality is of std::function objects is unfortunately not solvable in the generic sense.
Because the equivalence of Turing machines is undecidable. Given two different function objects, you cannot possibly determine if they compute the same function or not. [That answer was deleted]
I completely disagree with this: it is not the job of std::function to perform comparison itself; its job is just to redirect request to comparison to underlying objects - that's all.
If underlying object type does not define comparison - it will be a compilation error; in any case, std::function is not required to deduce a comparison algorithm.
If the underlying object type defines comparison, but which works wrongly, or has some unusual semantic - it is not the problem of std::function itself either, but it is problem of the underlying type.
It is possible to implement function_comparable based on std::function.
Here is a proof-of-concept:
template<typename Callback,typename Function> inline
bool func_compare(const Function &lhs,const Function &rhs)
{
typedef typename conditional
<
is_function<Callback>::value,
typename add_pointer<Callback>::type,
Callback
>::type request_type;
if (const request_type *lhs_internal = lhs.template target<request_type>())
if (const request_type *rhs_internal = rhs.template target<request_type>())
return *rhs_internal == *lhs_internal;
return false;
}
#if USE_VARIADIC_TEMPLATES
#define FUNC_SIG_TYPES typename ...Args
#define FUNC_SIG_TYPES_PASS Args...
#else
#define FUNC_SIG_TYPES typename function_signature
#define FUNC_SIG_TYPES_PASS function_signature
#endif
template<FUNC_SIG_TYPES>
struct function_comparable: function<FUNC_SIG_TYPES_PASS>
{
typedef function<FUNC_SIG_TYPES_PASS> Function;
bool (*type_holder)(const Function &,const Function &);
public:
function_comparable() {}
template<typename Func> function_comparable(Func f)
: Function(f), type_holder(func_compare<Func,Function>)
{
}
template<typename Func> function_comparable &operator=(Func f)
{
Function::operator=(f);
type_holder=func_compare<Func,Function>;
return *this;
}
friend bool operator==(const Function &lhs,const function_comparable &rhs)
{
return rhs.type_holder(lhs,rhs);
}
friend bool operator==(const function_comparable &lhs,const Function &rhs)
{
return rhs==lhs;
}
friend void swap(function_comparable &lhs,function_comparable &rhs)// noexcept
{
lhs.swap(rhs);
lhs.type_holder.swap(rhs.type_holder);
}
};
There is a nice property - function_comparable can be compared against std::function too.
For instance, let's say we have vector of std::functions, and we want to give users register_callback and unregister_callback functions. Use of function_comparable is required only for unregister_callback parameter:
void register_callback(std::function<function_signature> callback);
void unregister_callback(function_comparable<function_signature> callback);
Live demo at Ideone
Source code of demo:
// Copyright Evgeny Panasyuk 2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <type_traits>
#include <functional>
#include <algorithm>
#include <stdexcept>
#include <iostream>
#include <typeinfo>
#include <utility>
#include <ostream>
#include <vector>
#include <string>
using namespace std;
// _____________________________Implementation__________________________________________
#define USE_VARIADIC_TEMPLATES 0
template<typename Callback,typename Function> inline
bool func_compare(const Function &lhs,const Function &rhs)
{
typedef typename conditional
<
is_function<Callback>::value,
typename add_pointer<Callback>::type,
Callback
>::type request_type;
if (const request_type *lhs_internal = lhs.template target<request_type>())
if (const request_type *rhs_internal = rhs.template target<request_type>())
return *rhs_internal == *lhs_internal;
return false;
}
#if USE_VARIADIC_TEMPLATES
#define FUNC_SIG_TYPES typename ...Args
#define FUNC_SIG_TYPES_PASS Args...
#else
#define FUNC_SIG_TYPES typename function_signature
#define FUNC_SIG_TYPES_PASS function_signature
#endif
template<FUNC_SIG_TYPES>
struct function_comparable: function<FUNC_SIG_TYPES_PASS>
{
typedef function<FUNC_SIG_TYPES_PASS> Function;
bool (*type_holder)(const Function &,const Function &);
public:
function_comparable() {}
template<typename Func> function_comparable(Func f)
: Function(f), type_holder(func_compare<Func,Function>)
{
}
template<typename Func> function_comparable &operator=(Func f)
{
Function::operator=(f);
type_holder=func_compare<Func,Function>;
return *this;
}
friend bool operator==(const Function &lhs,const function_comparable &rhs)
{
return rhs.type_holder(lhs,rhs);
}
friend bool operator==(const function_comparable &lhs,const Function &rhs)
{
return rhs==lhs;
}
// ...
friend void swap(function_comparable &lhs,function_comparable &rhs)// noexcept
{
lhs.swap(rhs);
lhs.type_holder.swap(rhs.type_holder);
}
};
// ________________________________Example______________________________________________
typedef void (function_signature)();
void func1()
{
cout << "func1" << endl;
}
void func3()
{
cout << "func3" << endl;
}
class func2
{
int data;
public:
explicit func2(int n) : data(n) {}
friend bool operator==(const func2 &lhs,const func2 &rhs)
{
return lhs.data==rhs.data;
}
void operator()()
{
cout << "func2, data=" << data << endl;
}
};
struct Caller
{
template<typename Func>
void operator()(Func f)
{
f();
}
};
class Callbacks
{
vector<function<function_signature>> v;
public:
void register_callback_comparator(function_comparable<function_signature> callback)
{
v.push_back(callback);
}
void register_callback(function<function_signature> callback)
{
v.push_back(callback);
}
void unregister_callback(function_comparable<function_signature> callback)
{
auto it=find(v.begin(),v.end(),callback);
if(it!=v.end())
v.erase(it);
else
throw runtime_error("not found");
}
void call_all()
{
for_each(v.begin(),v.end(),Caller());
cout << string(16,'_') << endl;
}
};
int main()
{
Callbacks cb;
function_comparable<function_signature> f;
f=func1;
cb.register_callback_comparator(f);
cb.register_callback(func2(1));
cb.register_callback(func2(2));
cb.register_callback(func3);
cb.call_all();
cb.unregister_callback(func2(2));
cb.call_all();
cb.unregister_callback(func1);
cb.call_all();
}
Output is:
func1
func2, data=1
func2, data=2
func3
________________
func1
func2, data=1
func3
________________
func2, data=1
func3
________________
P.S. It seems that with help of std::type_index, it is possible to implement something similar to function_comparable class, which also supports ordering (i.e. std::less) or even hashing. Not only ordering between different types, but also ordering within same type (this requires support from types, like LessThanComparable).
According to http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#1240:
The leading comment here is part of
the history of std::function, which
was introduced with N1402. During that
time no explicit conversion functions
existed, and the "safe-bool" idiom
(based on pointers-to-member) was a
popular technique. The only
disadvantage of this idiom was that
given two objects f1 and f2 of type
std::function, the expression
f1 == f2;
was well-formed, just because the
built-in operator== for pointer to
member was considered after a single
user-defined conversion. To fix this,
an overload set of undefined
comparison functions was added, such
that overload resolution would prefer
those ending up in a linkage error.
The new language facility of deleted
functions provided a much better
diagnostic mechanism to fix this
issue.
In C++11, the deleted functions are considered superfluous with the introduction of explicit conversion operators, so they will probably be removed for C++11.
The central point of this issue is,
that with the replacement of the
safe-bool idiom by explicit conversion
to bool, the original "hole in the type
system" does no longer exist and
therefore the comment is wrong and the
superfluous function definitions
should be removed as well.
As for why you can't compare std::function objects, it's probably because they can possibly hold global/static functions, member functions, functors, etc, and to do that std::function "erases" some information about the underlying type. Implementing an equality operator would probably not be feasible because of that.
Actually, you can compare targets. It may work depends of what you want from comparison.
Here the code with inequality, but you can see how it works:
template <class Function>
struct Comparator
{
bool operator()(const Function& f1, const Function& f2) const
{
auto ptr1 = f1.target<Function>();
auto ptr2 = f2.target<Function>();
return ptr1 < ptr2;
}
};
typedef function<void(void)> Function;
set<Function, Comparator<Function>> setOfFunc;
void f11() {}
int _tmain(int argc, _TCHAR* argv[])
{
cout << "was inserted - " << setOfFunc.insert(bind(&f11)).second << endl; // 1 - inserted
cout << "was inserted - " << setOfFunc.insert(f11).second << endl; // 0 - not inserted
cout << "# of deleted is " << setOfFunc.erase(f11) << endl;
return 0;
}
Ups, it is only valid since C++11.
How about trying something like the following, this works well for testing templates.
if (std::is_same<T1, T2>::value)
{
...
}
the least that could be done is if std::function saves the address of the function used for binding to a string and used string comparison instead.