匿名命名空间内运算符的模板重载解析
Template overload resolution for operators inside an anonymous namespace
简短的问题:运算符是否有特殊的模板查找规则用于内部链接的重载解析,或者底部的代码是 GCC 中运算符的模板重载解析错误?
细节: 我将带您完成我的推理,而不是粘贴一大块代码。让我们从一些简单的代码开始:
#include <iostream>
template<typename T> struct A{ T b; };
struct B{};
template<typename T>
void foo (const A<T>&a) { foo(a.b); }
void foo (const B&) { std::cout << "hello"; }
int main(){
A<B> b;
foo(b);
}
上面打印"hello"
,一切正常。
现在让我们把 foo
都放在一个匿名命名空间中:
namespace {
template<typename T>
void foo (const A<T>&a) { foo(a.b); }
void foo (const B&) { std::cout << "hello"; }
}
代码现在无法编译。 Clang 说 error: call to function 'foo' that is neither visible in the template definition nor found by argument-dependent lookup
和 GCC template argument deduction/substitution failed
。
这是错误的,因为 foo(const B&)
是在 foo<T>
之后定义的,并且没有外部链接,如 n4296:
中所述
[basic.link]
An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has
internal linkage. All other namespaces have external linkage.
[temp.point]
The instantiation context of an expression that depends on the template arguments is the set of declarations
with external linkage declared prior to the point of instantiation of the template specialization in the same translation unit.
[temp.dep.candidate]
For a function call where the postfix-expression is a dependent name,
the candidate functions are found using the usual lookup rules (3.4.1,
3.4.2) except that:
For the part of the lookup using unqualified name lookup (3.4.1), only function declarations from the template
definition context are found.
For the part of the lookup using
associated namespaces (3.4.2), only function declarations found in
either the template definition context or the template instantiation
context are found.
现在使用运算符同样的事情:
struct ostream {} cout;
template<typename T> struct A{ T t; };
struct B{};
namespace {
template<typename T>
ostream& operator<< (ostream& out, const A<T>&v)
{ return out << v.t; }
ostream& operator<< (ostream& out, const B&)
{ return out; }
}
int main(){
A<B> a;
cout << a;
}
GCC (4.7/4.8/4.9) 现在对代码非常满意,并使用 -Wall -Wextra -pedantic -ansi
给出零警告,而 clang 抱怨 'operator<<'
与 foo
的方式相同.
我在标准中没有发现运算符重载查找的任何异常,所以我相信这是 GCC 中的一个错误(功能?),但模板解析规则并不容易,所以我想我可能会在提交错误之前检查这里.
您可以实时查看此代码 here。
这绝对是 gcc 中的错误。下面的代码正确地使用 clang 打印 right
但使用 GCC 打印 wrong
。
#include <iostream>
template<typename T> struct A{ T t; };
struct B{};
struct C : public B{};
std::ostream& operator<< (std::ostream& out, const B&)
{ return out << "right"; }
namespace {
template<typename T>
std::ostream& operator<< (std::ostream& out, const A<T>&v)
{ return out << v.t; }
std::ostream& operator<< (std::ostream& out, const C&)
{ return out << "wrong"; }
}
int main(){
A<C> a;
std::cout << a;
}
已举报here。
简短的问题:运算符是否有特殊的模板查找规则用于内部链接的重载解析,或者底部的代码是 GCC 中运算符的模板重载解析错误?
细节: 我将带您完成我的推理,而不是粘贴一大块代码。让我们从一些简单的代码开始:
#include <iostream>
template<typename T> struct A{ T b; };
struct B{};
template<typename T>
void foo (const A<T>&a) { foo(a.b); }
void foo (const B&) { std::cout << "hello"; }
int main(){
A<B> b;
foo(b);
}
上面打印"hello"
,一切正常。
现在让我们把 foo
都放在一个匿名命名空间中:
namespace {
template<typename T>
void foo (const A<T>&a) { foo(a.b); }
void foo (const B&) { std::cout << "hello"; }
}
代码现在无法编译。 Clang 说 error: call to function 'foo' that is neither visible in the template definition nor found by argument-dependent lookup
和 GCC template argument deduction/substitution failed
。
这是错误的,因为 foo(const B&)
是在 foo<T>
之后定义的,并且没有外部链接,如 n4296:
[basic.link] An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage. All other namespaces have external linkage.
[temp.point] The instantiation context of an expression that depends on the template arguments is the set of declarations with external linkage declared prior to the point of instantiation of the template specialization in the same translation unit.
[temp.dep.candidate] For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:
For the part of the lookup using unqualified name lookup (3.4.1), only function declarations from the template definition context are found.
For the part of the lookup using associated namespaces (3.4.2), only function declarations found in either the template definition context or the template instantiation context are found.
现在使用运算符同样的事情:
struct ostream {} cout;
template<typename T> struct A{ T t; };
struct B{};
namespace {
template<typename T>
ostream& operator<< (ostream& out, const A<T>&v)
{ return out << v.t; }
ostream& operator<< (ostream& out, const B&)
{ return out; }
}
int main(){
A<B> a;
cout << a;
}
GCC (4.7/4.8/4.9) 现在对代码非常满意,并使用 -Wall -Wextra -pedantic -ansi
给出零警告,而 clang 抱怨 'operator<<'
与 foo
的方式相同.
我在标准中没有发现运算符重载查找的任何异常,所以我相信这是 GCC 中的一个错误(功能?),但模板解析规则并不容易,所以我想我可能会在提交错误之前检查这里.
您可以实时查看此代码 here。
这绝对是 gcc 中的错误。下面的代码正确地使用 clang 打印 right
但使用 GCC 打印 wrong
。
#include <iostream>
template<typename T> struct A{ T t; };
struct B{};
struct C : public B{};
std::ostream& operator<< (std::ostream& out, const B&)
{ return out << "right"; }
namespace {
template<typename T>
std::ostream& operator<< (std::ostream& out, const A<T>&v)
{ return out << v.t; }
std::ostream& operator<< (std::ostream& out, const C&)
{ return out << "wrong"; }
}
int main(){
A<C> a;
std::cout << a;
}
已举报here。