operator<< for standard output and templates

A

aaragon

Hi everyone,

I was unable to find out why my code is not compiling. I have a
template class and I'm trying to write the operator<< for standard
output. Does anyone know why this is not right? The code is as
follows...

// main class:
template <
class Individual,
class SelectionPolicy,
class Population : public SelectionPolicy, public
CrossOverPolicy<Individual> {

// member variables and functions

// friend declaration for standard output
template <class I,class Se,template <class> class C,class St>
friend ostream& operator<<(ostream& os, Population<I,Se,C,St>& pop);

};

// operator<< definition
template <class Individual,class SelectionPolicy,template <class>
class CrossOverPolicy,class StoragePolicy>
ostream& operator<<(ostream& os,
Population<Individual,SelectionPolicy,CrossOverPolicy,StoragePolicy>&
pop) {

os<<"pop"<<endl;
return os;
}

// main function
int main(){

typedef Population<ind, t > pop;
pop ccc(10);
cout<<ccc<<endl;
return 0;
}

The compiler error message is:

main.cxx:104: error: ambiguous overload for 'operator<<' in 'std::cout
<< ccc'
gaPopulation.h:411: note: candidates are: std::eek:stream&
operator<<(std::eek:stream&, Population<I, Se, C, St>&) [with I =
Individual<Chromosome<Objective<1u, Optimizator<minimize> >,
BitSetPolicy, 2>, ClockMutator>, Se = TournamentSelector<2>, C =
OnePointX, St = VectorPolicy<Individual<Chromosome<Objective<1u,
Optimizator<minimize> >, BitSetPolicy, 2>, ClockMutator> >, Individual
= Individual<Chromosome<Objective<1u, Optimizator<minimize> >,
BitSetPolicy, 2>, ClockMutator>, SelectionPolicy =
CrossOverPolicy = OnePointX said:
, BitSetPolicy, 2>, ClockMutator> >]
gaPopulation.h:441: note: std::eek:stream&
operator<<(std::eek:stream&, Population<Individual, SelectionPolicy,
CrossOverPolicy, StoragePolicy>&) [with Individual =
Individual<Chromosome<Objective<1u, Optimizator<minimize> >,
BitSetPolicy, 2>, ClockMutator>, SelectionPolicy =
CrossOverPolicy = OnePointX said:
, BitSetPolicy, 2>, ClockMutator> >]
make[2]: *** [main.o] Error 1

Thank you,

a^2
 
J

James Kanze

I was unable to find out why my code is not compiling. I have a
template class and I'm trying to write the operator<< for standard
output. Does anyone know why this is not right? The code is as
follows...

Classical problem...
// main class:
template <
class Individual,
class SelectionPolicy,
template <class> class CrossOverPolicy = OnePointX,
class StoragePolicy = VectorPolicy<Individual>
class Population : public SelectionPolicy, public
CrossOverPolicy<Individual> {

// member variables and functions
// friend declaration for standard output
template <class I,class Se,template <class> class C,class St>
friend ostream& operator<<(ostream& os, Population<I,Se,C,St>& pop);

Here you declare for each instantiation of the template a
non-template function, which takes the specific instance. This
is the function that the compiler will try to call when you use
<< on the object.
// operator<< definition
template <class Individual,class SelectionPolicy,template <class>
class CrossOverPolicy,class StoragePolicy>
ostream& operator<<(ostream& os,
Population<Individual,SelectionPolicy,CrossOverPolicy,StoragePolicy>&
pop) {
os<<"pop"<<endl;
return os;
}

And here you've just defined a function template. You now have
two possible functions which can be called with <<.
// main function
int main(){

typedef Population<ind, t > pop;
pop ccc(10);
cout<<ccc<<endl;

The compiler sees the two functions, the template, and the
non-template. Both are equal matches, so the non-template is
chosen. And you don't have a definition of it, so the linker
complains.
return 0;

}
The compiler error message is:

main.cxx:104: error: ambiguous overload for 'operator<<' in 'std::cout
<< ccc'
gaPopulation.h:411: note: candidates are: std::eek:stream&
operator<<(std::eek:stream&, Population<I, Se, C, St>&) [with I =
Individual<Chromosome<Objective<1u, Optimizator<minimize> >,
BitSetPolicy, 2>, ClockMutator>, Se = TournamentSelector<2>, C =
OnePointX, St = VectorPolicy<Individual<Chromosome<Objective<1u,
Optimizator<minimize> >, BitSetPolicy, 2>, ClockMutator> >, Individual
= Individual<Chromosome<Objective<1u, Optimizator<minimize> >,
BitSetPolicy, 2>, ClockMutator>, SelectionPolicy =
TournamentSelector<2>, CrossOverPolicy = OnePointX, StoragePolicy =
VectorPolicy<Individual<Chromosome<Objective<1u, Optimizator<minimize>>, BitSetPolicy, 2>, ClockMutator> >]

I wouldn't have expected ambiguous. All other things being
equal, the compiler should prefer the non-template over the
template. Of course, that would just give you a linker error,
so you wouldn't get much further.

There are two simple solutions: provide the definition for the
operator<< in the friend declaration, or provide a non-friend
template function outside the class. (A non-friend or the
operator<< definition in the class can, of course, call other
member functions, e.g. you provide a member
print(std::eek:stream&), which is called by the template function
operator<<.)
 
A

aaragon

I was unable to find out why my code is not compiling. I have a
template class and I'm trying to write the operator<< for standard
output. Does anyone know why this is not right? The code is as
follows...

Classical problem...
// main class:
template <
class Individual,
class SelectionPolicy,
template <class> class CrossOverPolicy = OnePointX,
class StoragePolicy = VectorPolicy<Individual>
class Population : public SelectionPolicy, public
CrossOverPolicy<Individual> {
// member variables and functions
// friend declaration for standard output
template <class I,class Se,template <class> class C,class St>
friend ostream& operator<<(ostream& os, Population<I,Se,C,St>& pop);

Here you declare for each instantiation of the template a
non-template function, which takes the specific instance. This
is the function that the compiler will try to call when you use
<< on the object.
};
// operator<< definition
template <class Individual,class SelectionPolicy,template <class>
class CrossOverPolicy,class StoragePolicy>
ostream& operator<<(ostream& os,
Population<Individual,SelectionPolicy,CrossOverPolicy,StoragePolicy>&
pop) {
os<<"pop"<<endl;
return os;
}

And here you've just defined a function template. You now have
two possible functions which can be called with <<.
// main function
int main(){
typedef Population<ind, t > pop;
pop ccc(10);
cout<<ccc<<endl;

The compiler sees the two functions, the template, and the
non-template. Both are equal matches, so the non-template is
chosen. And you don't have a definition of it, so the linker
complains.


return 0;
}
The compiler error message is:
main.cxx:104: error: ambiguous overload for 'operator<<' in 'std::cout
<< ccc'
gaPopulation.h:411: note: candidates are: std::eek:stream&
operator<<(std::eek:stream&, Population<I, Se, C, St>&) [with I =
Individual<Chromosome<Objective<1u, Optimizator<minimize> >,
BitSetPolicy, 2>, ClockMutator>, Se = TournamentSelector<2>, C =
OnePointX, St = VectorPolicy<Individual<Chromosome<Objective<1u,
Optimizator<minimize> >, BitSetPolicy, 2>, ClockMutator> >, Individual
= Individual<Chromosome<Objective<1u, Optimizator<minimize> >,
BitSetPolicy, 2>, ClockMutator>, SelectionPolicy =
TournamentSelector<2>, CrossOverPolicy = OnePointX, StoragePolicy =
VectorPolicy<Individual<Chromosome<Objective<1u, Optimizator<minimize>>, BitSetPolicy, 2>, ClockMutator> >]

I wouldn't have expected ambiguous. All other things being
equal, the compiler should prefer the non-template over the
template. Of course, that would just give you a linker error,
so you wouldn't get much further.

There are two simple solutions: provide the definition for the
operator<< in the friend declaration, or provide a non-friend
template function outside the class. (A non-friend or the
operator<< definition in the class can, of course, call other
member functions, e.g. you provide a member
print(std::eek:stream&), which is called by the template function
operator<<.)

--
James Kanze (Gabi Software) email: (e-mail address removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Thank you James for your answer, I tried both ways and they work.
Something that I don't really understand is why the friend declaration
within the class is a non-template declaration? If you put the
template <template parameters> before the keyword 'friend', aren't you
declaring this as a template function?
Once again, thanks for the answer.
 
J

James Kanze

[...]
Thank you James for your answer, I tried both ways and they work.
Something that I don't really understand is why the friend declaration
within the class is a non-template declaration? If you put the
template <template parameters> before the keyword 'friend', aren't you
declaring this as a template function?
Once again, thanks for the answer.

I missed them. Originally, templates couldn't be friends; this
possibility was added to the standard. And in fact, the
standard actually contradicts itself here: the first sentence of
§11.4 (Friends) says that a friend is a function or a class that
is not a member of the class, and templates are neither
functions nor classes. §14.5.3 (Friends, but in the chapter on
templates), says that a friend can be a function template or
class template, a specialization of a function template or class
template, or an ordinary (nontemplate) function or class.
There's a definite contradiction there.

I'm not sure what the compiler is doing in your case. As I
said, I was surprised that it found an ambiguïty. If I
understand your code correctly, it should declare all of the
specializations of the template function as friend. There is
also a syntax to declare just a particular instantiation as
friend, something like:
friend ostream& operator<< <>( ... ) ;
I think (although maybe the declaration of the template must
precede the class definition). I'm not really sure, however, as
I always use one of the techniques I mentionned in my first
post.
 
A

aaragon

I was unable to find out why my code is not compiling. I have a
template class and I'm trying to write the operator<< for standard
output. Does anyone know why this is not right? The code is as
follows...
Classical problem...
// main class:
template <
class Individual,
class SelectionPolicy,
template <class> class CrossOverPolicy = OnePointX,
class StoragePolicy = VectorPolicy<Individual>
class Population : public SelectionPolicy, public
CrossOverPolicy<Individual> {
// member variables and functions
// friend declaration for standard output
template <class I,class Se,template <class> class C,class St>
friend ostream& operator<<(ostream& os, Population<I,Se,C,St>& pop);
Here you declare for each instantiation of the template a
non-template function, which takes the specific instance. This
is the function that the compiler will try to call when you use
<< on the object.
};
[...]
There are two simple solutions: provide the definition for the
operator<< in the friend declaration, or provide a non-friend
template function outside the class. (A non-friend or the
operator<< definition in the class can, of course, call other
member functions, e.g. you provide a member
print(std::eek:stream&), which is called by the template function
operator<<.)
Thank you James for your answer, I tried both ways and they work.
Something that I don't really understand is why the friend declaration
within the class is a non-template declaration? If you put the
template <template parameters> before the keyword 'friend', aren't you
declaring this as a template function?
Once again, thanks for the answer.

I missed them. Originally, templates couldn't be friends; this
possibility was added to the standard. And in fact, the
standard actually contradicts itself here: the first sentence of
§11.4 (Friends) says that a friend is a function or a class that
is not a member of the class, and templates are neither
functions nor classes. §14.5.3 (Friends, but in the chapter on
templates), says that a friend can be a function template or
class template, a specialization of a function template or class
template, or an ordinary (nontemplate) function or class.
There's a definite contradiction there.

I'm not sure what the compiler is doing in your case. As I
said, I was surprised that it found an ambiguïty. If I
understand your code correctly, it should declare all of the
specializations of the template function as friend. There is
also a syntax to declare just a particular instantiation as
friend, something like:
friend ostream& operator<< <>( ... ) ;
I think (although maybe the declaration of the template must
precede the class definition). I'm not really sure, however, as
I always use one of the techniques I mentionned in my first
post.

--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

James, thank you once again for your insight on this, it has been very
helpful.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,610
Members
45,255
Latest member
TopCryptoTwitterChannels

Latest Threads

Top