My explicit instantiation of template class seems doesn't work - c++

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.

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(); }
}

understanding operator lookup; which compiler is correct?

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.

Why does implicit == on map<<int,MyClass> not compile?

I have a strange issue defining == for one of my class.
I simplified the code here to an example that i tested on my visual 2013;
MyClass is defined in namespace N
This does compile:
N::MyClass a, b;
bool test = a == b;
This too:
const N::MyClass a, b;
bool test = a == b;
This does not compile
std::map<int, N::MyClass> a, b;
bool test = a == b;
For your information the == operator is declared like this :
bool operator==(const N::MyClass & a, const N::MyClass & b);
here is the error I get : error C2678: binary '==' : no operator found which takes a left-hand operand of type 'const MyClass' (or there is no acceptable conversion)
But from what I know the map operator is defined : map == reference on cppreference.com
could someone explain me why this is wrong ?
Thank you in advance.
I did not find an answer and I'm sorry if this is stupid.
[solution]
If I mode the operator into the namespace it works :
bool N::operator==(const MyClass & a, const MyClass & b);
But I don't know why I need to do that, is it in the language definition ? (I guess yes)
Based on your description, I guess your equality operator is not defined in the same namespace as your class. The following demonstrates the situation:
#include <map>
namespace foo
{
class bar
{
};
}
using namespace foo;
bool operator== (bar const&, bar const&) { return true; }
int main()
{
bar const b;
b == b; // OK
std::map<int, bar> mb;
mb == mb; // ERROR
}
The obvious fix is to define the equality operator in the same namespace as the class. The reason it doesn't work is the two-phase name look-up in templates: when a templates is instantiated it only does second phase name look-up, i.e., it only finds functions relating to template arguments based on explicit qualification or argument dependent look-up. The equality operator isn't qualified in std::map<K, V> (well, it is never qualified when using operator notation to call it) and, thus, it needs to be found by argument dependent look-up.
Your MyClass::operator== needs to be marked const. For example:
bool operator ==(const MyClass&) const;
Note that your operator:
bool operator==(const MyClass & a, const MyClass & b);
will not work. operator== only takes one argument and compares this and the passed argument.
Unless it's not a class member operator, but a non-member one. In this case, it's correct and should work. Since it doesn't, it suggests to me that you forgot to #include the header file where your operator is declared.

C++ adding friend to a template class in order to typecast

I'm currently reading "Effective C++" and there is a chapter that contains code similiar to this:
template <typename T>
class Num {
public:
Num(int n) { ... }
};
template <typename T>
Num<T> operator*(const Num<T>& lhs, const Num<T>& rhs) { ... }
Num<int> n = 5 * Num<int>(10);
The book says that this won't work (and indeed it doesn't) because you can't expect the compiler to use implicit typecasting to specialize a template.
As a soluting it is suggested to use the "friend" syntax to define the function inside the class.
//It works
template <typename T>
class Num {
public:
Num(int n) { ... }
friend
Num operator*(const Num& lhs, const Num& rhs) { ... }
};
Num<int> n = 5 * Num<int>(10);
And the book suggests to use this friend-declaration thing whenever I need implicit conversion to a template class type. And it all seems to make sense.
But why can't I get the same example working with a common function, not an operator?
template <typename T>
class Num {
public:
Num(int n) { ... }
friend
void doFoo(const Num& lhs) { ... }
};
doFoo(5);
This time the compiler complaints that he can't find any 'doFoo' at all.
And if i declare the doFoo outside the class, i get the reasonable mismatched types error. Seems like the "friend ..." part is just being ignored.
So is there a problem with my understanding? What is the difference between a function and an operator in this case?
The reason is that here
doFoo(5);
the compiler has no way of finding foo, given an int parameter. This would be the equivalent of calling your friend operator like this:
Num<int> n = 5 * 10;
This will "work", but not by calling the friend operator* defined in your Num class, but by calling the built-in operator* for integers, and then using the implicit conversion from Num's converting constructor.
The core problem is lookup. A friend declaration provides a declaration of a namespace level function, but the declaration is only available inside the class that is befriending it. In the example the book provides that is not an issue: the function takes two arguments of the enclosing type, as long as one of them is of the enclosing type, Argument Dependent Lookup will look inside the definition of the class and find the operator. In your case that is not the case, since there is a single argument and that needs a conversion, the compiler will not look inside the definition of the class.
Note that this is regardless of templates and conversions:
class A {
friend void f( int ) {}
friend void g( int, A ) {}
};
int main() {
f(5); // Error: lookup cannot find 'f' declared *only* inside A
g(5,A()); // Ok, one argument is 'A', lookup will find the function
}
In the case above, where there are no templates involved, you could potentially add a declaration at namespace level to fix it, but that is not really an option for template classes.
class A {
friend void f() { std::cout << "inside A\n"; }
};
void f(int); // only declaration
int main() {
f(5); // "inside A"
}
This cannot be done for a template (and for all instantiating types) as the friend declaration is a declaration of a non-templated function. Although you could can play with the code just for the sake of testing:
template <typename T>
struct Num {
Num(int x) ...
friend void f( Num const & );
};
Num<int> f(Num<int> const &); // only declaration
int main() {
f(5);
}
Yes these code compiler do not know how to work with it .
like
doFoo(5)
compiler do not know 5 is int

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.