将'typedef'从基础类传播到'模板'的派生类


67

我试图定义只包含typedef的基类。

template<typename T>
class A
{
public:
    typedef std::vector<T> Vec_t;
};


template<typename T>
class B : public A<T>
{
private:
    Vec_t v;  // fails - Vec_t is not recognized
};

为什么在BI中收到无法识别Vec_t的错误,我需要显式地编写它?

typename A<T>::Vec_t v;


12
好吧,这并不是一个确切的重复,因为您提到的文章谈论的是方法,而本文则讨论类型。
Matthieu M.

2
类型名称A :: Vec_t v; 很好 那里不需要<T>
Johan Lundberg'8

Answers:


45

我相信这个问题是重复的,但我现在找不到。C ++ Standard表示您应根据14.6.2 / 3完全限定名称:

在类模板或类模板的成员的定义中,如果类模板的基类取决于template-parameter,则在的定义时,在非限定名称查找期间都不会检查基类作用域模板或成员,或在类模板或成员的实例化期间。

UPD:我终于找到了重复项:在这里


24
顺便说一句,总是让我感到烦恼的是我必须对所有内容进行“重新定义”……这并不令人愉快,一点也不令人愉快。
Matthieu M.

14
顺便说一句,排位赛时不需要所有模板参数和所有参数。由于有注入的类名,因此足以编写typename B::Vec_t
Johannes Schaub-litb

@ JohannesSchaub-litb我正按照您所说的去做,但是如果我没有为B指定模板参数,则会出错。(B不是类,名称空间或枚举)
Gonzalo Solera

@GonzaloSolera我有同样的错误结果,但仅在我的一个平台上,一个具有较旧的C ++标准。我想知道是否完全符合资格的要求在某个时候改变了?
srm

41

在模板的情况下,有一些叫做依赖和依赖的名称。

如果名称依赖于模板参数T,则其依赖名称以及不依赖参数T的其他名称均为独立名称。

这是规则:编译器在查找非依赖名称(例如Vec_t)时不查找依赖基类(例如A)。结果,编译器不知道它们甚至不存在类型。

Vec_t除非知道,否则编译器无法假定该类型是T因为数据成员A<T>在哪里可能存在特殊化A<T>:: Vec_t

所以解决方法是使用typename

 typename A<T>::Vec_t v;  ← good

我建议您仔细阅读以下https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-types

旧的(断开的)链接:http : //www.parashift.com/c++-faq-lite/templates.html#faq-35.18


1
除了解释之外,您的答案似乎是唯一可以提供解决方案的答案。谢谢。
理查德

如果您通知我您已更正链接,我将为您提供+1。
乔纳森·梅

8

因为编译器不确定是否Vec_t命名类型。例如,A<T>可能是专门用于T=int具有特定的typedef


对于T类型变量,A<T>仅进行前向声明,而没有定义。只能A<t>在哪里t定义类型(不是类型变量)(通过专门化模板定义或通过显式专门化)。IOW,即使您从C ++中删除了模板显式和部分专业化模板(并且没有更改其他任何东西),也仍然不正确。
curiousguy 2012年

6

为了完整起见,以下是您可以稍微减轻这种麻烦的方法:

  • 在派生类中重新typedef那些类型,或更佳-与方法一样-
  • 只需使用以下命令将这些名称导入派生类范围中using declaration

template<typename T>
class A
{
public:
    typedef std::vector<T> Vec_t;
};


template<typename T>
class B : public A<T>
{
public:
    using typename A<T>::Vec_t;
    // .........

private:
    Vec_t v;
};

如果typedef在派生类中对继承项的提及不止一个,它可能会很有用。另外,您不需要typename每次都添加此内容。


你有错字 using typename A::Vec_t;应该是using typename A<T>::Vec_t;
NathanOliver

2

您需要明确限定使用,Vec_t因为编译器不知道其Vec_t来源。

它不能假定有关A的结构的任何信息,因为类模板A可能是专用的。专门化可以包括Vec_t不是typedef的a,或者甚至根本不包括成员Vec_t


1

Vec_t不是从属名称,并且编译器需要在不实例化任何模板的情况下知道其含义(在这种情况下为基类)。确实与以下内容没有什么不同:

template <class T>
class X
{
    std::string s;
}

即使在X未被实例化的情况下,编译器也需要知道std :: string,因为名称不依赖于模板参数T(就编译器可以假定的而言)。

总而言之,模板基类中的typedef对于在派生类中使用似乎毫无用处。但是,typedef对用户很有用。


你的意思是class X : T {这里吗?
curiousguy 2012年

1

这个概念可以和我们的使用方式联系起来std::vector<T>。例如,如果我们有一个std::vector<int> Foo。现在,我们决定使用它的任何成员类型,比如说iterator。在这种情况下,我们明确提到

std::vector<int>::iterator foo_iterator;

同样,在你的情况下,为了使用公共成员类型Vec_ttemplate <typename T> class A,你需要明确地声明为

A<T>::Vec_t v;
OR
A<int>::Vec_t int_type;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.