难以理解C ++依赖类型,以及当前实例的内容 [英] Trouble understanding C++ dependent types, vs what's on the current instantiation

查看:81
本文介绍了难以理解C ++依赖类型,以及当前实例的内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码是根据此处的答案改编而成的: https://stackoverflow.com/a/17579889/352552

The code below is adapted from the answer here: https://stackoverflow.com/a/17579889/352552

我问这个问题的目的是试图更好地理解C ++如何处理依赖类型周围的类型解析,而不是当前实例中的内容,因此不需要 typename 限定词。我一直在从不同的编译器获得矛盾的结果,所以我来这里是为了寻找更规范的答案。

My purpose in asking this question is try to to understand better how C++ handles type resolution around dependent types, versus what's considered to be on the current instantiation, and therefore not needing a typename qualifier. I've been getting contradictory results from different compilers, so I've come here looking for a more canonical answer.

考虑以下代码

#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。在海湾合作委员会,我愿意。到现在为止还挺好。

line A) in show(), if I understand correctly, tells the compiler to use the current instantiation, so I should get INT INT. On GCC, I do. So far, so good.

B行,如果我理解正确的话,应该告诉编译器考虑依赖类型,这将使​​该行出错,原因是模棱两可或者,如果这意味着 only 仅考虑依赖类型,则应获取INT FLOAT。在GCC上,我也在那里获得INT INT。为什么?

Line B, again if I understand correctly, should either tell the compiler to consider dependent types, which would make that line error out because of the ambiguity; or, if that means only consider dependent types, I should get INT FLOAT. On GCC I get INT INT there, too. Why?

在Clang上运行此操作。

Running this on Clang.

A行


错误:D中没有名为 result_type的类型;您的意思仅仅是 result_type吗? D :: result_type r1;

error: no type named 'result_type' in 'D'; did you mean simply 'result_type'? D::result_type r1;

删除 D :: 确实会产生INT INT。

dropping the D:: does indeed yield INT INT.

应该编译,还是Clang在这里正确?

Should it have compiled, or is Clang correct here?

B行确实在歧义上出错

Line B does indeed error on the ambiguity


错误:在类型为D :: result_type r1的多个基类中找到成员'result_type'

error: member 'result_type' found in multiple base classes of different types typename D::result_type r1






这里有人可以授权说哪个编译器(如果有的话)是正确的,为什么?


Can anyone here say with authority which compiler (if any!) is canonically correct, and why?

假设Clang是正确的,则可能暗示

Assuming Clang is correct, it might imply that

MyType :: F

如果存在于基本类型上,则不能从当前实例中引用该类型;只有在 that 类中定义了类型时,该参数才有效。即添加

is invalid for referencing a type from the current instantiation if it exists on a base type; it's only valid if the type is defined on that class. Ie adding

typedef double dd;

D

然后

D::dd d = 1.1;
std::cout<<d;

show 中可以正常工作,这

此外,

typename D :: sometype

似乎是指<考虑>考虑的依赖类型,但不是排他性的,因此,如果这种类型在

seems to mean consider dependent types, but not exclusively, and so expect errors if such a type winds up defined in multiple places, either in the current instantiation, and or dependent on a template parameter.

但是同样,这一切都假定Clang的行为根据规范是正确的,我可以做到这一点。

But again, this all assumes Clang's behavior is correct according to spec, which I can't speak to.

我正在使用的指向GCC的链接:
https://wandbox.org/

Link to GCC repl I was using: https://wandbox.org/

链接到我正在使用的Clang repl:
https://repl.it/languages/cpp11

Link to Clang repl I was using: https://repl.it/languages/cpp11

推荐答案


此外,

Moreover,

typename D ::某些类型

似乎意味着要考虑从属类型

seems to mean consider dependent types

您从何处得到这个想法? typename 仅表示后面的不是数据成员,而是类型名称,因此可以完成模板的解析。您是否知道原始的C ++编译器过去是如何解析模板函数和类的?他们没有进行有意义的解析,只是吃掉了所有符号后才进行 { / } 平衡。是的,如果从未实例化模板定义,几乎可以在模板定义中包括几乎所有垃圾!这是简单而又肮脏的,但是如果您考虑一下,那并不是那么愚蠢,因为当时的替代方案(正确的解析)实际上并不切实可行。

Where did you get that idea? typename only means that what follows isn't a data member but a type name, so that the parsing of a template can be done. Do you know how primitive C++ compilers parsed template functions and classes in the old time? They did no meaningful parsing, they just ate all symbols doing only {/} balancing. Yes at some point you could include almost any garbage inside template definitions if they were never instantiated! It was simplistic and dirty but not that inane if you think about it, as the alternative (correct parsing) was not really practicable at the time.

在模板内部解析(甚至不解析很多名称)时,需要使某些事情变得明确:在实例化之前无法解析的符号的类别(变量或函数,类型名称,模板名称),所以像 X * Y; X *(Y); X(Y); 是模棱两可且不可解析的(声明或表达式)。 所以 typename 用来表示在模板定义时找不到的符号指定了类型,因此,如果 X typename T :: U ,则前面的三个标记都是声明的;没有 typename 且如果 T :: U 是依赖的,它们将被解析为表达式语句,并且没有第二个在实例化模板时进行解析,因此如果 U 实际上是一种类型,则将是错误。

In order to even meaningfully parse (without even resolving many names) inside a template some things need to be made explicit: the category (variable-or-function, type name, template name) of symbols that can't be resolved before instantiation, so simple stuff like X * Y;, X * (Y); and X(Y); is ambiguous and not parsable (declaration or expression). So typename is used to indicate that a symbol that can't be found at template definition time designate a type, so if X is typename T::U then all three previous syntagmes are declaration; without the typename and if T::U is dependent they would be parse as expression-statements and there is no second parsing when templates are instantiated so if U was actually a type it would be an error.


//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 从当前实例中查找仅考虑了非依赖的基类在定义时,然后:

According to https://en.cppreference.com/w/cpp/language/dependent_name lookup from the "current instantiation" considers only non dependent base classes at definition time and then:


如果对当前实例化成员的查找在两个实例之间给出了不同的
结果实例化点和定义点,
的查询是不明确的。

If the lookup of a member of current instantiation gives a different result between the point of instantiation and the point of definition, the lookup is ambiguous.

所以希望您希望进行的操作不会发生!

So hopefully what you "hoped" for shouldn't happen!

这篇关于难以理解C ++依赖类型,以及当前实例的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆