依赖名称的模板消歧器
The template disambiguator for dependent names
此问题基于C++引用部分:依赖名称-依赖名称的模板消歧器。
我已经理解,当调用模板类中的模板成员函数时,关键字template是必要的,以使编译器知道下面的括号用于指示模板参数。就像本节中使用的示例一样。
template<typename T>
struct S {
template<typename U> void foo(){}
};
template<typename T>
void bar()
{
S<T> s;
s.foo<T>(); // error: < parsed as less than operator
s.template foo<T>(); // OK
}
然而,在后面的部分中,它描述了当模板名称出现在成员访问表达式中时(在->之后或在.之后),如果在表达式的上下文中通过普通查找找到了具有相同名称的模板,则消歧器是不必要的。
然后它附带了以下代码。与前面的例子相比,它定义了集合函数,其名称也存在于标准库中。同时,使用std::set设置,使set模板在template函数中可见。在这种情况下,即使没有提供关键字模板,它仍然可以很好地工作。
#include <set>
using std::set; // makes 'set' visible to lookup from bar
template<typename T>
struct S {
template<typename U> void set(){}
};
template<typename T>
void bar()
{
S<T> s;
s.set<T>(); // not an error if ::set is visible:
// (and since C++11, this is well-formed)
s.template set<T>(); // works with and without ::set
}
根据我的理解,我尝试了自己的版本
#include <iostream>
template <typename T>
struct S{
template <typename U> void func(){
std::cout << "In S::funcn";
}
};
// In order to make member template function is visible in function test,
// defining a global template function **func** whose name is same with one
// member template function in struct S.
template <typename M>
void func(){
std::cout << "from ordinary funcn";
}
template <typename M>
void test(){
S<M> s;
func<M>(); // test func template function is visible in test function
s.func<M>();
}
int main(){
test<int>();
}
详细错误消息如下所示
[17:17:50][ryu@C++_test]$ g++ -g typename2.cpp
typename2.cpp:61:7: error: use 'template' keyword to treat 'func' as a dependent
template name
s.func<M>();
^
template
1 error generated.
任何关于如何使我自己的代码在没有关键字模板的情况下运行良好的建议都将不胜感激。
短版本
不要依赖这个。按照你的意愿使用template
关键字,不要为了避免几次击键而尝试这种晦涩难懂的破解方法。你的代码绝对不应该按照标准编译,你从cppreference.com引用的例子可能很快也会被明确禁止(我认为它一开始就不有效)。GCC和Clang对于这两个实例产生不同的结果。即使它们今天编译,明天在下一个编译器版本中也可能失败。
长版本
关于来自cppreference.com的示例,让我们首先注意Clang 3.6.0编译代码,但GCC 5.1.0拒绝s.set<T>()
和s.template set<T>()
,并返回错误invalid use of 'class std::set<T>'
。我认为根据标准,这两个编译器中的任何一个都没有做正确的事情,但是,直观地说,GCC的错误消息很有意义:s.set<T>()
和set<T>
是类模板专用化的含义是什么?
对于您的代码,情况正好相反:Clang拒绝它(问题中引用的错误消息似乎实际上来自Clang),GCC编译它。
这些例子依赖于标准中的[3.4.5p1]段(所有引用的重点都是我的):
在类成员访问表达式(5.2.5)中,如果。或->令牌为紧随其后的是标识符,后跟<,标识符必须查找以确定<是一个模板参数列表(14.2)或小于运算符。标识符首先在对象表达式的类中查找。如果找不到标识符,然后在整个后缀表达式,并应命名一个类模板。
类模板部分是您的代码被Clang拒绝的原因(您的 似乎没有任何情况下使用非成员模板函数可以很好地作为类的id表达式成员访问表达式。 我认为这说明了这个查找规则的意图:它应该找到格式良好的结构;它并不是为了让解析器对那些具有一些临时匹配的 即使使用上面的特殊查找规则,我也不确定在这种情况下标准是否允许您省略 当成员模板专用化的名称出现在后面时。或->在后缀表达式中,或在限定id中的嵌套名称说明符之后,并且后缀表达式的对象表达式为限定id中的类型相关或嵌套的名称说明符引用到依赖类型,但该名称不是当前类型的成员实例化(14.6.2.1),成员模板名称必须以为前缀关键字CCD_ 10。否则,该名称将被假定为非模板。 两个示例中的成员模板 或者,换言之,如果你想将 如果名称不依赖于模板参数(如中所定义14.6.2),该名称的声明(或声明集)应在该名称出现在模板中时的范围内释义名称绑定到声明并且此绑定不受声明的影响在实例化时可见。 绑定后,它被刻在石头上,随后切换到成员模板无效,这使得cppreference.com示例不正确。 此外,关于[3.4.5p1]中查找规则对此类示例的适用性,还有一个悬而未决的问题——问题1835。引用其中的注释: 一种可能是将查找限制为对象表达式时的对象表达式。 该问题处于起草阶段,这意味着工作组已达成非正式共识。这一共识究竟是什么还有待观察,但我想说,很有可能会有所改变。依赖这样的代码似乎不是一个好主意。 从C++11到当前工作草案(N4431),引用的段落保持不变。func
是函数模板<>
感到满意,这些临时匹配稍后将被具有完全不同语义的其他内容所取代。template
。第[14.2p4]段说:set
和func
分别满足其中的条件。正如你所看到的,这条规则没有提到任何例外。set
解析为成员模板的名称,它前面必须有template
。如果没有,它可以解析为命名空间范围set
,但set
名称本身不再是依赖于模板参数的名称(set<T>
仍然是依赖的,但set
本身不是)。然后我们进入[14.6p10],上面写着:
- 如何从C++中的依赖类型中获得它所依赖的类型
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- 将依赖名称显式标记为类型名和模板的奇怪之处
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- C++GTKMM gui循环依赖关系
- 通过ccmake在cmake中缓存依赖选项
- 当基类是依赖类型时,这是一个缺陷吗
- 从不同的附加依赖项中识别等同命名的函数
- 如何在 CMake 中对目标依赖项进行分组?
- 是否可以依赖函数范围的静态变量来执行程序关闭期间调用的方法?
- 为什么构建目录中新构建的共享库与安装目录中的副本具有不同的依赖项集?
- VS 2015 链接错误 无法构建依赖于 libcurl 的项目
- 通过依赖类型使用非类型模板参数的单类型模板参数类模板的部分专用化
- 为什么内存屏障依赖于变量?
- node-gyp 的先有鸡还是先有蛋的问题:指向依赖项中的头文件
- 反转依赖于 end() 的迭代器
- GCC,CMake,预编译标头和维护依赖项
- 使用 'typename' 关键字将非类型视为依赖上下文中的类型
- 使用 Git 处理 C++ Visual Studio 2019 解决方案的外部依赖项源代码管理的最佳方法是什么?
- 为什么依赖模板类型在部分专用化中不可推导?