I created a class Chromosome that ended up simply being a wrapper for vector with an ostream operator, so I've decided to typedef vector instead. However, I'm having trouble with the templated ostream operator... Is this the best way to go about it? (I've seen a few approaches and have failed to get any to work)
template<typename G>
class Chromosome {
public:
typedef typename std::vector<G> type;
typedef typename std::pair<type *,type *> ptr_pair;
};
template<typename G> //line 19 below:
std::ostream& operator<<(std::ostream& os, const Chromosome<G>::type& chromosome) {
for(auto iter = chromosome.begin(); iter != chromosome.end(); ++iter)
std::cout << *iter;
return os;
}
At the moment the error I'm getting is:
chromosome.h:19: error: expected unqualified-id before ‘&’ token
chromosome.h:19: error: expected ‘)’ before ‘&’ token
chromosome.h:19: error: expected initializer before ‘&’ token
Cheers.
Unfortunately, there's no clean way to do this because the compiler can't deduce the type of G
from the function declaration
template<typename G>
std::ostream& operator<<(std::ostream& os, const typename Chromosome<G>::type& chromosome);
The reason is that if you were to specialize Chromosome
for different types, you could end up in a situation where the compiler couldn't unambiguously infer G
. For example:
template <typename G> class Chromosome {
public:
typedef std::vector<G> type; // No typename needed here, BTW
};
template <> class Chromosome<int> {
public:
typedef std::vector<double> type;
};
Now, what would happen if you did this?
vector<double> v;
cout << v << endl;
The compiler can't tell if G
is double
or int
in this case, because both Chromosome<int>
and Chromosome<double>
have vector<double>
as their nested type.
To fix this, you'll have to explicitly use the type vector<G>
as the argument:
template<typename G>
std::ostream& operator<<(std::ostream& os, const std::vector<G>& chromosome);
Unfortunately, there really isn't a better way of doing this. It's not really a defect in the language, since there's a good reason to prohibit it, but it does actually prevent you from doing what you want to in this context.
The member typedef type
is a dependent name: its meaning is dependent upon the template parameter G
. You need to use a typename
to tell the compiler that type
names a type:
const typename Chromosome<G>::type&
For the full explanation, consider reading the Stack Overflow C++ FAQ article, Where to put the “template” and “typename” on dependent names.
As @templatetypedef alludes to in the comments, while this will enable the code to compile, it won't "work" to allow you to insert an std::vector<G>
into an std::ostream
because type
is in a nondeduced context.
The easiest way to declare the overload and get the expected behavior is to use std::vector<G>
directly as the argument type:
template<typename G>
std::ostream& operator<<(std::ostream& os, const std::vector<G>& chromosome)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With