难以理解C++依赖类型与当前实例化上的内容
Trouble understanding C++ dependent types, vs what's on the current instantiation
下面的代码改编自这里的答案: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;
}
行 A) 在show()
中,如果我理解正确,告诉编译器使用当前实例化,所以我应该得到 INT INT。 在海湾合作委员会,我愿意。目前为止,一切都好。
B行,同样,如果我理解正确的话,应该告诉编译器考虑依赖类型,由于歧义,这将使该行出错;或者,如果这意味着只考虑依赖类型,我应该得到INT FLOAT。 在海湾合作委员会上,我也在那里得到INT INT。 为什么?
在 Clang 上运行这个。
A 行根本不编译。
错误:在"D"中没有名为"result_type"的类型;你的意思是简单的"result_type"吗?D::result_type r1;
放弃D::
确实会产生 INT INT。
它应该编译,还是这里的 Clang 是正确的?
B行确实在歧义上犯了错误
错误:在不同类型的多个基类中找到成员"result_type" 类型名 D::result_type R1
这里的任何人都可以权威地说哪个编译器(如果有的话!)是规范正确的,为什么?
假设Clang是正确的,这可能意味着
MyType::F
如果基类型上存在类型,则对于从当前实例化引用类型无效;仅当在该类上定义了类型时,它才有效。 即添加
typedef double dd;
到D
然后
D::dd d = 1.1;
std::cout<<d;
在show
会工作得很好,事实确实如此。
此外
typename D::sometype
似乎意味着考虑依赖类型,但不完全考虑,因此如果此类类型最终在多个位置定义,无论是在当前实例化中还是依赖于模板参数,则会出现错误。
但同样,这一切都假设 Clang 的行为根据规范是正确的,我无法与之交谈。
链接到我正在使用的 GCC repl: https://wandbox.org/
链接到我正在使用的 Clang repl: https://repl.it/languages/cpp11
此外,
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 从"当前实例化"中查找,在定义时仅考虑非依赖基类,然后:
如果对当前实例化成员的查找给出不同的 实例化点和定义点之间的结果, 查找不明确。
所以希望你"希望"的事情不应该发生!
- 从C++实例化QML
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 如何创建一个空的全局类并在启动时实例化它
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 约束和显式模板实例化
- 为什么包含windows.h会产生语法错误,从而阻止类的实例化?(C2146,C2065)
- 对象实例化调用构造函数的次数太多
- 如何使用非默认构造函数实例化模板化类
- 静态数据成员模板专用化的实例化点在哪里
- 错误的cv::face FacemarkLBF实例化
- C++的解析器在可以区分比较和模板实例化之前会做什么?
- 为什么 gcc 和 clang 为函数模板的实例化生成不同的符号名称?
- 检查某些类型是否是模板类 std::optional 的实例化
- 我有一个对象,它将在整个程序的持续时间内实例化,但一个类成员不会,我应该动态分配它吗?
- 无法使用 SWIG 在 Python 中实例化C++类(获取属性错误)
- 模板化类构造函数的模板实例化
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 受约束的成员函数和显式模板实例化
- 对显式实例化的模板函数的未定义引用
- [temp.variadic]中关于包扩展实例化的措辞