- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
当编译器尝试解析i.template hi<T>();
时它发现hi
在全局命名空间中而不是方法 hi
上i
(ideone)。为什么?
#include <cstdio>
// Define 'hi' and 'bye' in the global namespace; these should *not* be used
template<typename T> struct hi { };
template<typename T> struct bye { };
// Foo needs to be templated for Foo::Inner to be a dependent type (I think)
template<typename T>
struct Foo
{
struct Inner {
// This is a plain-old templated member function of Inner, yes?
template<typename U>
void hi() { std::printf("hi!\n"); }
// This is a plain-old member function of Inner
void bye() { std::printf("bye!\n"); }
};
void sayStuff()
{
Inner i;
i.template hi<T>(); // Fails to compile -- finds global hi instead of member
i.bye(); // Compiles fine, finds member
}
};
int main() {
Foo<int> f;
f.sayStuff();
return 0;
}
我正在使用 g++ 4.9.1/4.9.2 ( -std=c++11
)。确切的错误消息:
prog.cpp: In member function 'void Foo<T>::sayStuff()':
prog.cpp:19:5: error: invalid use of 'struct hi<T>'
i.template hi<T>();
^
此代码在 Clang 和 VS2013 中运行良好,但在 g++ 和 EDG 中生成错误。但哪些编译器是正确的?
除了更改成员(member)姓名之外,还有什么办法可以解决这个问题吗?在我的真实代码中,当 std
中的类型出现时,就会出现冲突。命名空间(例如通过 using namespace std
导入的)与我的成员函数之一具有相同的名称。显然,我希望我的实现代码是健壮的,并且不会导致用户代码中的随机名称冲突。
最佳答案
据我所知,这就是正在发生的事情。
DR228说:
[Voted into WP at April 2003 meeting.]
Consider the following example:
template<class T>
struct X {
virtual void f();
};
template<class T>
struct Y {
void g(X<T> *p) {
p->template X<T>::f();
}
};
This is an error because X is not a member template; 14.2 [temp.names] paragraph 5 says:
If a name prefixed by the keyword template is not the name of a member template, the program is ill-formed.
在某种程度上,这是完全有道理的:即使 p 具有依赖类型,但使用普通查找发现 X 是一个模板。然而,我认为这使得模板前缀的使用变得更加难以教授。
这是故意禁止的吗?
提议的决议(4/02):
删除 14.2 [temp.names] 第 5 段中第一次使用的“member”一词,使其第一句如下:
If a name prefixed by the keyword template is not the name of a template, the program is ill-formed.
但是,在最新公开的 C++ 标准草案 N4296 中§14.2.5 中出现以下措辞:
A name prefixed by the keyword template shall be a template-id or the name shall refer to a class template. [Note: The keyword
template
may not be applied to non-template members of class templates. —end note] [Note: As is the case with thetypename
prefix, thetemplate
prefix is allowed in cases where it is not strictly necessary; i.e., when the nested-name-specifier or the expression on the left of the->
or.
is not dependent on a template-parameter, or the use does not appear in the scope of a template. —end note][Example:
template <class T> struct A {
void f(int);
template <class U> void f(U);
};
template <class T> void f(T t) {
A<T> a;
a.template f<>(t); // OK: calls template
a.template f(t); // error: not a template-id
}
template <class T> struct B {
template <class T2> struct C { };
};
// OK: T::template C names a class template:
template <class T, template <class X> class TT = T::template C> struct D { };
D<B<int> > db;—end example]
这个措辞听起来很相似,但不同之处足以值得挖掘。我发现在N3126草案措辞已更改为此版本。
我能够将此更改链接回此 DR96 :
The following is the wording from 14.2 [temp.names] paragraphs 4 and 5 that discusses the use of the "template" keyword following . or -> and in qualified names.
{snip}
The whole point of this feature is to say that the "template" keyword is needed to indicate that a "<" begins a template parameter list in certain contexts. The constraints in paragraph 5 leave open to debate certain cases.
First, I think it should be made more clear that the template name must be followed by a template argument list when the "template" keyword is used in these contexts. If we don't make this clear, we would have to add several semantic clarifications instead. For example, if you say "p->template f()", and "f" is an overload set containing both templates and nontemplates: a) is this valid? b) are the nontemplates in the overload set ignored? If the user is forced to write "p->template f<>()" it is clear that this is valid, and it is equally clear that nontemplates in the overload set are ignored. As this feature was added purely to provide syntactic guidance, I think it is important that it otherwise have no semantic implications.
本质上,DR228 的细微变化在后续版本中丢失了;但是,由于没有设置类似的限制,除非标准中存在其他修订,否则 DR228 的意图可能仍然有效。这意味着在这种情况下,模板查找必须在全局范围内进行,即使它是依赖类型。
让我们看看我们的名称查找规则§3.4.5.1:
In a class member access expression (5.2.5), if the
.
or->
token is immediately followed by an identifier followed by a<
, the identifier must be looked up to determine whether the<
is the beginning of a template argument list (14.2) or a less-than operator. The identifier is first looked up in the class of the object expression. If the identifier is not found, it is then looked up in the context of the entire postfix-expression and shall name a class template.这似乎明确指出
baz.foo->template bar<T>();
我们将首先查看类上下文,这包括标准模板查找。完成之后,如果没有找到任何内容,如果表达式的形式正确,我们就会跳转到整个表达式的上下文。本质上,它已经被提升,如果该行只是读取template bar<T>();
,则对该名称的查找必须以相同的方式执行。确实,我们已经从 DR228 中知道了这一点。我只是想仔细检查并确认。真正的问题是哪个模板应该获得优先级,全局范围内的模板还是类范围内的模板。为此,我们现在需要询问非限定名称查找,因为现在 bar 与 foo 在同一上下文中被考虑,因此它不再遵循成员查找规则,而是遵循正常的非限定模板查找规则,这自然更喜欢本地版本。
总而言之,Clang 和 MSVC 似乎表现出了正确的行为,而 GCC 和 EDG 在这种情况下却没有表现出正确的行为。
我对 GCC 错误原因的最佳猜测是在触发规则后选择了错误的上下文分配给表达式。它可能只是偶然将其放置在全局级别,而不是将上下文放置在与后缀表达式相同的级别?也许它只是跳过第一个查找步骤? (但这只是猜测,我必须真正弄清楚在 GCC 源代码中查找的位置。)这也可以解释为什么 @Mikael Persson 将查找更改为合格的解决方案会导致编译重新开始。
来自提问者的链接错误报告让人们谈论为什么必须考虑全局范围,而且应该如此,但似乎很简单,本地范围匹配必须比全局范围匹配具有更高的优先级。最近那里似乎也有一些事件。
关于c++ - 为什么这个依赖名称查找找到的是全局标识符而不是方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27930448/
我在 gobject 上阅读了一个维基百科页面,上面写着, Depending only on GLib and libc, GObject is a cornerstone of GNOME and
如何注册一个依赖属性,其值是使用另一个依赖属性的值计算的? 由于 .NET 属性包装器在运行时被 WPF 绕过,因此不应在 getter 和 setter 中包含逻辑。解决方案通常是使用 Proper
我一直在尝试将 ActionbarSherlock maven 依赖项添加到我的项目中 com.actionbarsherlock library 4.2.0 在我的 po
http://tutorials.jenkov.com/ood/understanding-dependencies.html#whatis说(强调我的): Whenever a class A us
我对所有这些魔法有点不清楚。 据我了解,依赖属性是从 DependencyObject 继承的,因此存储值: 如果分配了值(在本地字典中),则在实例本身中 或者如果未指定值,则从指向父元素的链接中获取
我刚刚更新了在 ASP.NET Framework 4.5.2 版上运行的 MVC Web 应用程序。我正在使用 Twilio 发送 SMS 消息: var twilio = new TwilioRe
我刚刚发现了一件令人生畏的事情。 spring 依赖坐标有两个版本。 项目依赖于 spring mvc 和 spring flow。有两组并行的依赖项。 Spring MVC 具有以下方案的依赖项
我正在尝试包含 的 maven 依赖项 org.jacorb jacorb 2.3.1 依赖已解决,但它导致另一个依赖 picocontainer 出现问题: [ERROR
我正在尝试在 Haskell 项目中包含特定版本的库。该库是住宿加早餐型的(用于 martix 操作),但我需要特定的 0.4.3 版本,该版本修复了乘法实现的错误。 所以,我的 stack.yaml
有谁知道如何制作依赖的 UIPickerView.例如,当我选择组件一的第 2 行时,组件二的标题会发生变化吗? 我在互联网上查找过,没有真正的答案,我尝试过使用 if 和 switch 语句,但它们
我正在编写一个用于验收测试的项目,由于各种原因,这依赖于另一个打包为 WAR 的项目。我已成功使用 maven-dependency-plugin 解压 WAR,但无法让我的项目包含解压的 WEB-I
或多或少我在 session 上大量构建我的网站(特别是重定向用户等),我很好奇这是否是一种危险的做法。禁用浏览器 cookie 保存的用户的大致比例是多少?我愿意接受任何建议:) 谢谢 最佳答案 s
开始玩 Scala futures,我被依赖的 futures 困住了。 让我们举个例子。我搜索地点并获得 Future[Seq[Place]]。对于这些地点中的每一个,我搜索最近的地铁站(该服务返回
或多或少我在 session 上大量构建我的网站(特别是重定向用户等),我很好奇这是否是一种危险的做法。禁用浏览器 cookie 保存的用户的大致比例是多少?我愿意接受任何建议:) 谢谢 最佳答案 s
我有一个二进制文件,需要一些 *.so 文件才能执行。现在,当我尝试在一些旧机器上执行它时,它会显示 /lib/libc.so.6: version `GLIBC_2.4' not found 如何将
我尝试使用 Dygraph 来表示图表,我在 https://github.com/danvk/dygraphs 中找到了代码,但是它有太多的依赖文件,我觉得很烦人。是否有一个文件可以容纳所有必需的
我正在处理一个 javascript 文件,该文件 a) 声明一个具有函数的对象,并且 b) 使用它期望在外部声明的散列调用该对象的 init 函数。我的 Jasmine 规范提示它找不到哈希,因为它
最近我一直在学习 Angular 并且进展顺利,但是关于依赖注入(inject)的一些事情我仍然不清楚。 是否有任何理由在我的 app.js 文件中声明我的应用程序的其他部分(服务、 Controll
考虑一个名为 foo 的表,它有 id (PRIMARY & AUTO_INCREMENT) 列。我正在向该表中插入一行,挑战从此时开始。 $db->query("INSERT INTO `foo`
我正在使用级联下拉 jquery 插件。 (https://github.com/dnasir/jquery-cascading-dropdown) 我有两个下拉菜单。 “客户端”和“站点”。 根据您
我是一名优秀的程序员,十分优秀!