如果我有两个班级:
template <typename T>
struct Node
{
...
};
tempalte <typename T_Node, typename T>
struct NodeIterator
{
T m_value;
};
NodeIterator<Node<int>, int>
我可以从T
推断模板参数T_Node
,而不会让Node
类显式创建类似这样的typedef:
// 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> >
如果没有,是否有一个原因我不能这样做(编译器已经知道T_Node
和它所采用的类型T
)除了“该功能不存在用C ++“?我问这个问题,因为通常有一个很简单的事情(至少在表面上),就像语言中缺少的一样。
答案 0 :(得分:2)
为什么不将NodeIterator
更改为类似的内容:
template <typename T>
struct NodeIterator
{
typedef Node<T> node_type;
node_type m_value;
};
这应该允许您创建NodeIterator<int>
类型的对象。我认为这将是一个优雅的解决方案。
`
答案 1 :(得分:2)
没有typedef,那是不可能的。关键是编译器不知道T_Node
本身就是模板的实例化。 Node<T>
只是类型,仅此而已。
C ++知道三层实体:值,类型和模板。 Node
是一个模板,Node<T>
是一种类型。当您的类模板接受类型参数时,您无法再检查该类型的性质。
通过部分特化进行模式匹配是提取此类信息的唯一方法,并且您无需进行一些功能元编程。任何类型的检查通常被称为“类型特征”。这一切都归结为同样的事情,非常类似于你已经提出的建议,但也许这是另一种更通用的方式:
template <typename> struct ClassWithOneArg;
template <template <typename> class C, typename T>
struct ClassWithOneArg<C<T>>
{
typedef T value_type;
};
现在你可以说:typedef typename ClassWithOneArg<T_Node>::value_type type;
。
答案 2 :(得分:1)
是。你尝试过的几乎是正确的,除了你忘了typename
:
typedef typename T_Node::node_type node_type;
//^^^^^^^ note this!
您需要编写关键字typename
,因为嵌套类型node_type
是依赖类型。
答案 3 :(得分:0)
它不在语言中的原因很简单:没有人在标准化过程中提出这样一个功能的好建议。这可能是因为这样的功能并非无足轻重。为什么你可能只是对获取模板参数感到满意,还有很多其他的地方需要考虑才能使整个功能看起来“圆”。
当你感兴趣时,你可以制定出这样的建议;)
答案 4 :(得分:0)
我认为你不能,但我认为你不应该这样做。使用typedef是一种成熟的做法;查看标准容器及其value_type
等typedef。
您在另一个答案的评论中提到您不希望NodeIterator
了解Node
。它没有具体了解Node
;它只需要其模板参数为某些类型,其中包含node_type
类型。这可能是Node
,也可能是其他内容,NodeIterator
无需了解或关注。
答案 5 :(得分:0)
答案是否定的,你不能用C ++做到这一点。这就是为什么STL迭代器类型包含您试图避免的那些嵌套的typedef。此外,如果您想允许指向节点的指针(符合RandomAccessIterators的所有要求),依赖于这些嵌套类型会让您遇到麻烦。如果要将节点的原始指针包含为节点迭代器类型,则需要使用traits类,因为它们不能具有嵌套类型。