以下代码是根据此处的答案改编而成的:https://stackoverflow.com/a/17579889/352552
我问这个问题的目的是试图更好地理解C ++如何处理依赖类型的类型解析,而不是当前实例化上的解析,因此不需要typename
限定符。我一直在从不同的编译器获得矛盾的结果,所以我来这里是为了寻找更规范的答案。
考虑此代码
#include <iostream>
struct B {
typedef int result_type;
};
template<typename T>
struct C {
};
template<>
struct C<float> {
typedef float result_type;
};
template<typename T>
struct D : B, C<T> {
std::string show() {
//A) Default to current instantiation - ignore dependent type, even if one exists, or so I hope
D::result_type r1;
//B) What **exactly** does typename add, here?
//typename D::result_type r1;
return whichType(r1);
}
std::string whichType (int val){
return "INT";
}
std::string whichType (float val){
return "FLOAT";
}
};
int main() {
D<std::string> stringD;
D<float> floatD;
std::cout<<"String initialization "<<stringD.show()<<std::endl;
std::cout<<"Float initialization "<<floatD.show()<<std::endl;
}
如果我正确理解,show()
中的A行会告诉编译器使用当前实例化,因此我应该获得INT INT。在海湾合作委员会,我愿意。到目前为止,一切都很好。
如果我理解正确的话,B行应该告诉编译器考虑依赖类型,这会由于歧义而使该行出错。或者,如果这意味着 only 仅考虑依赖类型,则应该获取INT FLOAT。在GCC上,我也在那里获得INT INT。为什么?
在Clang上运行。
A行根本不编译。
错误:“ D”中没有名为“ result_type”的类型;您的意思仅仅是“ result_type”吗? D :: result_type r1;
丢弃D::
确实会产生INT INT。
它应该已编译,还是Clang在这里正确?
B行确实在歧义上出错
错误:在类型类型为D :: result_type r1的多个不同类型的多个基类中找到成员'result_type'
这里有人可以授权说哪个编译器(如果有的话)是正确的,为什么?
假设Clang是正确的,则可能暗示
MyType::F
如果存在于基本类型上,则对于从当前实例中引用类型无效;仅在 that 类中定义了类型时才有效。即添加
typedef double dd;
到D
然后
D::dd d = 1.1;
std::cout<<d;
在show
中可以正常工作,的确如此。
此外,
typename D::sometype
似乎意味着 consider 依赖类型,但不是排他性的,因此,如果这种类型在当前实例化或依赖于模板参数的多个位置结束定义,则可能会出现错误。
但是,这再次假设Clang的行为根据规范是正确的,我无法与之交谈。
我正在使用的指向GCC repl的链接: https://wandbox.org/
链接到我正在使用的Clang repl: https://repl.it/languages/cpp11
答案 0 :(得分:0)
此外,
typename D::sometype
似乎意味着要考虑依赖类型
您是从哪里得到这个主意的? typename
仅表示其后的不是数据成员,而是类型名称,因此可以完成模板的解析。您是否知道原始的C ++编译器过去是如何解析模板函数和类的?他们没有进行有意义的解析,只是吃掉了所有符号而仅进行{
/ }
平衡。是的,如果从未实例化模板定义,则几乎可以在模板定义中包括几乎所有垃圾!考虑到它是简单而肮脏的,但并不是那么愚蠢,因为当时的替代方案(正确解析)实际上并不可行。
为了在模板内部进行有意义的解析(甚至不解析很多名称),需要明确一些内容:无法解析的符号的类别(变量或函数,类型名称,模板名称)在实例化之前,像X * Y;
,X * (Y);
和X(Y);
这样的简单东西是模棱两可的,并且不可解析(声明或表达式)。 因此,typename
用于表示在模板定义时找不到的符号指定了类型,因此,如果X
为typename T::U
,则所有这三个符号先前的同义词是声明;如果没有typename
,并且如果T::U
是从属的,则它们将被解析为表达式语句,并且在实例化模板时没有第二次解析,因此如果U
实际上是一种类型,那将是一个错误
//A) Default to current instantiation - ignore dependent type, even if one exists, or so I hope D::result_type r1;
根据“当前实例”中的https://en.cppreference.com/w/cpp/language/dependent_name查找,在定义时仅考虑非依赖基类,然后:
如果当前实例成员的查找给出了不同的结果 实例化点与定义点之间的结果, 查找不明确。
因此,希望您“希望”实现的目标不应该发生!