我在另一个模板类中有一个嵌套的模板类:
template<typename T>
struct A
{
template<typename V>
struct B {};
};
嵌套类型B
的非成员operator==
的签名是什么?下面的简单尝试是行不通的:
template<typename T, typename V>
bool operator==(A<T>::B<V> left, A<T>::B<V> right);
Clang,GCC和MSVC给出了各种不同的错误和/或提示什么是错误的,例如缺少template
关键字,但我没有尝试解决它的工作。
请注意,这显然是有效的:
template<typename T>
struct A
{
template<typename V>
struct B {};
template<typename V>
friend bool operator==(B<V> left, B<V> right)
{
return true;
}
};
**然而,我需要离线非成员声明的原因是使用qdoc记录它。qdoc使用clang来解析源代码,它要求我提供operator==
的声明,我实际上已经实现了,就像刚才所示的那样。
3条答案
按热度按时间mnowg1ta1#
这个错误并不遥远,因为您需要template关键字,而且还需要typename来表示依赖类型。工作示例的形式如下:
但我建议:
作为减轻所需的一些深奥语法的手段。这是一个奇怪的一次性的东西,你会期望typename足以表示::B是A的依赖名,但你仍然需要template关键字,因为解析器在处理
<
和>
时会出了名的混淆。This answer很好地解释了原因:在name lookup(3.4)发现一个name是一个template-name之后,如果这个name后面跟一个<,<总是被当作一个template-argument-list的开头,而永远不会被当作一个name后面跟一个小于运算符。
现在我们回到了与typename相同的问题。如果我们在解析代码时还不能知道这个名字是否是一个模板,该怎么办?我们需要在模板名称前插入模板,如14.2/4所述。这看起来像:
t::template f<int>(); // call a function template
vlf7wbxs2#
直接的方法
typename A<T>::template B<V> left
不能按预期工作,因为A<T>::
是一个嵌套的名称说明符,它是一个非推导的上下文。T
必须显式传递:operator==<int>(a, b)
。为了保持
==
可用作二元运算符,可以使用SFINAE实现一个离线非成员声明:godbolt上的完整示例:点击。
u0njafvf3#
您可以有内联友元声明和大纲定义
然而gcc警告说
warning:friend declaration
bool operator==(A<T>::B<V>, A<T>::B<V>)
声明了一个非模板函数[-Wnon-template-friend]注意:(如果这不是你想要的,请确保函数模板已经被声明,并在函数名后面添加
<>
)为了修复这个警告,我们必须在
B
的定义之前转发声明operator==(B left, B right)
,这只能在A
内部,这将迫使它也成为A
的朋友。