考虑以下几点:
template<typename T>
struct C {};
template<typename T, typename U>
void operator +(C<T>&, U);
struct D: C<D> {};
struct E {};
template<typename T>
void operator +(C<T>&, E);
void F() { D d; E e; d + e; }
此代码在 GCC-7 和 Clang-5 上都能正常编译。 operator +
的选定重载是 struct E
的重载。
现在,如果发生以下变化:
/* Put `operator +` inside the class. */
template<typename T>
struct C {
template<typename U>
void operator +(U);
};
也就是说,如果 operator +
被定义在 inside 类模板中,而不是 outside,那么 Clang 会在两个 之间产生歧义运算符 +
存在于代码中。 GCC 仍然可以正常编译。
为什么会这样?这是 GCC 或 Clang 中的错误吗?
最佳答案
这是 gcc 中的一个错误;具体来说,https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53499 .
问题在于 gcc 将类模板成员函数的隐式对象参数视为具有依赖类型;也就是说,在函数模板部分排序 gcc 转换期间
C<D>::template<class U> void operator+(U); // #1
进入
template<class T, class U> void operator+(C<T>&, U); // #1a (gcc, wrong)
什么时候应该变成
template<class U> void operator+(C<D>&, U); // #1b (clang, correct)
与您的相比,我们可以看到
template<class T> void operator+(C<T>&, E); // #2
#2
优于错误的#1a
, 但与 #1b
不明确.
观察到 gcc 错误地接受了 C<D>
根本不是模板 - 即,当 C<D>
是一个完全特化的类模板:
template<class> struct C;
struct D;
template<> struct C<D> {
// ...
这被 [temp.func.order]/3 覆盖,在示例中进行了说明。再次注意,gcc 错误编译了该示例,错误地拒绝了它,但出于同样的原因。
关于c++ - Clang 中不明确的运算符重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48219096/