I want to implement a template function using nested-types of a template-class.
I have just read here that it is better to implement operator << as non-member and non-friend function. Therefore I decided to move functions toStream() and tableToStream() outside MyClass:
template <typename T>
class MyClass
{
public:
typedef boost::dynamic_bitset<> BoolTable;
typedef std::vector<T> MsgTable;
private:
BoolTable b_;
MsgTable m_;
public:
const BoolTable& getB() const { return b_; }
const MsgTable & getM() const { return m_; }
std::ostream& toStream (std::ostream& os) const
{
os <<"Bool: "; tableToStream (os, getB()); os <<'\n';
os <<"Msg:"; tableToStream (os, getM()); os <<'\n';
return os;
}
template <typename TABLE>
std::ostream& tableToStream (std::ostream& os, const TABLE& table) const
{
for (int i=0; i < table.size(); ++i)
os << table[i] <<',';
return os;
}
};
template <typename T>
std::ostream& operator << (std::ostream& os, const MyClass<T> mc)
{
return mc.toStream(os);
}
It’s easy to convert MyClass::toStream() into an operator << non-member and non-friend function:
template <typename T>
std::ostream& operator << (std::ostream& os, const MyClass<T>& mc)
{
os <<"Bool: "; mc.tableToStream (os, mc.getB()); os <<'\n';
os <<"Msg:"; mc.tableToStream (os, mc.getM()); os <<'\n';
return os;
}
But I want to use solely operator << instead of calling MyClass::tableToStream():
template <typename T>
std::ostream& operator << (std::ostream& os, const MyClass<T>& mc)
{
os <<"Bool: "<< mc.getB() <<'\n';
os <<"Msg:" << mc.getM() <<'\n';
return os;
}
For the function MyClass::tableToStream() I could use the following implementation, but this may mess the stream output because the function is too generic (any type can be TABLE).
template <typename TABLE>
std::ostream& operator << (std::ostream& os, const TABLE& table)
{
for (int i=0; i < table.size(); ++i)
os << table[i] <<',';
return os;
}
Therefore, I want to restrict to the nested types of MyClass. Below is one of my attempts to convert MyClass::tableToStream() into a standard operator << non-member and non-friend function:
template <typename T, typename MyClass<T>::TABLE>
std::ostream& operator << (std::ostream& os, const TABLE& table)
{
for (int i=0; i < table.size(); ++i)
os << table[i] <<',';
return os;
}
But the error is about typename MyClass<T>::TABLE.
Since you have clarified your question a lot, my first answer does not apply any more and I’ll remove-edit it to give you something that might fit better:
Updated answer:
You want to constrain the template to accept only types that are typedeffed inside your MyClass template. Such constraints are usually achieved by application of SFINAE, especially by
std::enable_if(orboost::enable_if, if your library lacks that part of C++11 support). Sadly, there is no traits like ais_typedeffed_insidethat could be used for your case. It’s even worse: there is no way to write such a trait just using the plain typedefs, since there is nothing special about being typedeffed inside a given class – the compiler has no way to determine (and is not interested in) if a given known type has some alias name for it somewhere.But if your typedefs are just the ones you show in your question, I have good news for you: you need exactly two
operator<<for that:boost::dynamic_bitset<>, since that is the BoolTable for any MyClass instantiation.std::vector<T>, since that is the MsgTable for each correspondingMyClass<T>.The downside is, that with this templated
operator<<, you’d be able to output anystd::vector<FooBar>, even ifFooBaris completely unrelated to any use of MyClass. But that holds for any other possible implementation of the properoperator<<‘s – if there’s no explicit restriction on the MSG parameter, there’s no restriction on a FooBar making astd::vector<FooBar>a viableMyClass<MSG>::MsgTable.My conclusion for your question: you wanted to have the
operator<<for its convenient looks, since it is normally used for thet purpose. In your case, you can provide it forMyClass<MSG>objects, but there is no way to do so for the inner typedefs alone.I’d implement it that way: