我正在浏览WildMagic 5引擎(www.geometrictools.com),其中Vector<> class继承自元组<>具有特定大小的数组的类,名为mTuple[]
(由模板参数设置)。到目前为止这么好,没什么特别的。但是,在Vector类中,我看到以下内容:
protected:
using Tuple<4,Real>::mTuple;
现在我知道using
关键字用于正确继承重载方法。在这种情况下,我总是假设变量可用于派生类而无需键入上面的代码。以上是必要的吗?还是只是为了让事情更清楚?
答案 0 :(得分:9)
通用编程与面向对象编程略有不同。
您的mTuple
是非依赖名称的示例。就编译器而言,在处理模板定义时,编译器不知道类模板是否继承了名为mTuple
的数据成员。这对您来说可能是显而易见的,但对编译器来说并不明显。在这个阶段,编译器忽略了显而易见的事情。
如果派生类模板的方法希望使用父类模板的某些成员,则需要明确告知编译器这样做。因此using
。
修改强>
上面的内容有点简洁。重要的是要记住,那些类模板不是类。它们是最终定义类的模板。直到类模板用于定义类模板不太真实的类的时刻。更重要的是,对于从其他类模板继承的类模板,该继承不是很真实。除非明确告知它,否则编译器不知道该继承。这就是为什么你会看到派生类模板通过using ParentClass<Type>::member
导入父类的成员(例如)。
编辑#2
Marshall Cline在他的C ++ - http://www.parashift.com/c++-faq-lite/templates.html#faq-35.19
的常见问题解答中讨论了这个主题编辑#3
(每个请求)仅仅因为某些代码在上编译编译器并不意味着它在每个编译器上编译(对于相同的语言)。编译器供应商将自己的“功能”添加到一种语言中,有时非常有意,有时只是因为供应商自己搞砸了,有时候因为标准本身就是错误的。这个不太标准的编译器问题长期以来一直是许多语言的问题。在泛型编程方面,这个问题显然非常猖獗。
你可以做任何事情(或者你认为):打开所有标准警告然后一些,通过一些商业代码分析器运行你的代码,你仍然可能没有可移植的代码。
答案 1 :(得分:8)
@David一直在说什么,但有些人显然没有理解。所以我相信一个例子是有序的:
template<typename T>
struct A { int a; };
template<typename T>
struct B : A<T> {
void f() {
a = 0; // #1
this->a = 0; // #2
B::a = 0; // #3
}
// using A<T>::a;
};
template<>
struct A<float> { }; // surprise!
#1
会导致错误,因为模板中的,非限定查找不会调查依赖基类。这是C ++中的一个重要概念。如果全局a
可见,则a
将使用a = 0
- 在依赖基类中声明的成员将从不隐藏该全局{ {1}}。为了告诉编译器查看依赖的基类,您必须限定您的名称。所以a
和this->a
一样正常。
如果您放置B::a
,则告诉编译器在using A<T>::a
范围内声明成员名称a
。然后B
将直接在a = 0
中找到a
。这也是一个可以接受的解决方案。
答案 2 :(得分:1)