Fill template of one class from another template class
If I have two classes:
template <typename T>
struct Node
{
...
};
tempalte <typename T_Node, typename T>
struct NodeIterator
{
T m_value;
};
NodeIterator<Node<int>, int>
can I deduce the template argument T
from T_Node
without the class Node
explicitly creating a typedef like this:
// To make it clear, yes I know this works, but I had to typedef the type
template <typename T>
struct Node
{
typedef T node_type;
...
};
template <typename T_Node>
struct NoteIterator
{
typedef typename T_Node::node_type node_type;
node_type m_value;
};
NodeIterator<Node<int> >
If not, is there a开发者_JAVA百科 reason why I cannot do that (the compiler already knows about T_Node
and the type T
it took in) apart from "the feature is just not there in C++"? I ask this as usually there is a good reason for something simple (at least on the surface) like this missing from the language.
Without the typedef, that's not possible. The point is that the compiler has no idea that T_Node
is itself an instantiation of a template. Node<T>
is just a type, nothing more.
C++ knows three tiers of entities: values, types, and templates. Node
is a template, and Node<T>
is a type. When your class template accepts a type parameter, then you have no further way to inspect the nature of that type.
Pattern matching through partial specialization is the only way to extract such information, and you don't get around a bit of functional metaprogramming. Any sort of type inspection is usually referred to as a "type trait". It'll all boil down to the same thing, very similar to what you already suggested, but perhaps here's another, more generic way:
template <typename> struct ClassWithOneArg;
template <template <typename> class C, typename T>
struct ClassWithOneArg<C<T>>
{
typedef T value_type;
};
Now you can say: typedef typename ClassWithOneArg<T_Node>::value_type type;
.
Why dont't you change the NodeIterator
to something like that:
template <typename T>
struct NodeIterator
{
typedef Node<T> node_type;
node_type m_value;
};
this should allow you to create objects of the type NodeIterator<int>
. I think this would be an elegant solution.
`
Yes. What you've tried is almost correct, except that you forgot typename
:
typedef typename T_Node::node_type node_type;
//^^^^^^^ note this!
You need to write the keyword typename
because the nested type node_type
is a dependent type.
No, you can't. You need the typedef. C++ does not have any compile time reflection support, where this feature would fit in.
The reason why it is not in the language is simple: No one came up with a good proposal for such a feature in the standardization process. This is probably becasue such a feature is not trivial. Why you might be just happy with getting hands on the template parameters, there are lots of other places that would need to be considered to make the feature as a whole look "round".
You could work out such a proposal when intrested ;)
I don't think you can, but I don't think you should need to either. Using typedefs for this is a well-established practice; look at the standard containers and their value_type
, etc. typedefs.
You mentioned in a comment on another answer that you don't want NodeIterator
to know about Node
. It doesn't have to know about Node
specifically; it just requires that its template argument be some type that contains a node_type
type within it. That could be Node
or it could be something else, and NodeIterator
doesn't have to know or care.
The answer is no, you cannot do that in C++. This is why STL iterator types contain those nested typedefs that you're trying to avoid. Also, relying on those nested types is going to get you in trouble if you want to allow pointers to Nodes (which fit all the requirements for RandomAccessIterators). You'll need to use traits classes if you want to include raw pointers to Nodes as node iterator types, since they cannot have nested types.
精彩评论