ryu*_*ryu 8 c++ templates c++11
此问题基于C++参考部分:依赖名称 - 依赖名称的模板消歧器.
我已经理解在模板类中调用模板成员函数时,关键字模板是必要的,以使编译器知道以下括号用于指示模板参数.就像本节中使用的示例一样.
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
}
Run Code Online (Sandbox Code Playgroud)
但是,在后续部分中,它描述了模板名称何时出现在成员访问表达式中(在 - >之后或之后.),如果在表达式的上下文中存在通过普通查找找到的具有相同名称的模板,则不需要消除歧义. ..
然后它附带以下代码.与前面的例子相比,它定义了set函数,其名称也存在于标准库中.同时,使用std :: set设置为在模板函数中显示设置模板.在这种情况下,即使没有提供关键字模板,它仍然可以正常工作.
#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
}
Run Code Online (Sandbox Code Playgroud)
根据我的理解,我尝试了自己的版本
#include <iostream>
template <typename T>
struct S{
template <typename U> void func(){
std::cout << "In S::func\n";
}
};
// 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 func\n";
}
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>();
}
Run Code Online (Sandbox Code Playgroud)
详细错误消息如下所示
[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.
Run Code Online (Sandbox Code Playgroud)
如果没有关键字模板使我自己的代码运行良好,任何建议表示赞赏.
不要依赖这个 template按照您的预期使用关键字,不要仅仅为了避免几次击键而尝试这种晦涩的技巧。您的代码绝对不应该根据该标准进行编译,并且您从cppreference.com引用的示例也可能很快被明确禁止(我认为它一开始就无效)。对于这两个示例,GCC和Clang得出不同的结果。即使今天进行编译,它们也可能明天在下一个编译器版本中失败。
对于来自cppreference.com的示例,我们首先要注意Clang 3.6.0会编译代码,但是GCC 5.1.0会同时拒绝两者s.set<T>()和s.template set<T>()error invalid use of 'class std::set<T>'。我不并根据这里的标准是正确的思考或者两种编译器,但是,直觉上,海湾合作委员会的错误信息,使有很大的意义:这将是意义s.set<T>()与set<T>作为一类模板特殊化?
对于您的代码,这是另一回事:Clang拒绝它(问题中引用的错误消息似乎实际上来自Clang),GCC对其进行编译。
这些示例依赖于标准中的第[3.4.5p1]段(在所有引号中都强调我的意思):
在类成员访问表达式(5.2.5)中,如果。或->标记后紧跟一个标识符,后跟一个<,必须查询该标识符以确定<是模板参数列表(14.2)的开始还是小于运算符。首先在对象表达式的类中查找标识符。如果找不到标识符,则在整个postfix-expression的上下文中查找它,并命名一个类模板。
在类模板部分是锵被拒绝了你的代码的原因(你func是一个函数模板)。从那里删除了功能模板,以解决C ++ 11中包含的缺陷141。值得一提的是缺陷报告中的评论:
似乎没有任何情况可以很好地使用非成员模板函数作为类成员访问表达式的id表达式。
我认为这说明了此查找规则的意图:应该查找结构良好的构造;这并不是要让解析器对那些<>具有某些临时匹配的解析器感到满意,这些解析稍后会被语义完全不同的其他事物替换。
即使使用上面的特殊查找规则,我也不确定template在这种情况下该标准是否允许您省略。第[14.2p4]段说:
当成员模板专门化名称出现在之后。或->在postfix-expression中或在限定id中的嵌套名称说明符之后,并且postfix-expression的对象表达式取决于类型,或者qualified-id中的嵌套名称说明符引用一个依赖类型,但名称不是当前实例(14.6.2.1)的成员,成员模板名称必须以关键字前缀
template。否则,假定该名称命名为非模板。
成员模板set和func两个示例中的成员模板分别满足其中的条件。如您所见,此规则未提及任何例外。
或者,换句话说,如果要set解析为成员模板的名称,则必须template在其前面。如果不是,则可以将其解析为namespace-scope set,但是set名称本身不再是依赖于模板参数的名称(set<T>仍然依赖于模板参数,但set本身不依赖于模板)。然后我们进入[14.6p10],它表示:
如果名称不依赖模板参数(如14.6.2中定义),则该名称的声明(或声明集)应在该名称出现在模板定义中的范围内;该名称绑定到在该点找到的一个(或多个)声明,并且此绑定不受实例化时可见的声明的影响。
绑定后,将其刻在石头上,随后切换到成员模板无效,这将导致cppreference.com示例不正确。
此外,关于从[3.4.5p1]到此类示例的查找规则的适用性,还有一个未解决的问题- 问题1835。在其中引用注释:
一种可能是当对象表达式从属时将查找限制在对象表达式的类中。
该问题处于起草状态,这意味着工作组已达成非正式共识。确切的共识还有待观察,但我想很有可能会有所改变。依靠这样的代码似乎不是一个好主意。
从C ++ 11到当前的工作草案(N4431),引用的段落一直保持不变。
| 归档时间: |
|
| 查看次数: |
765 次 |
| 最近记录: |