c++ - Clang 中不明确的运算符重载

标签 c++ templates gcc clang language-lawyer

考虑以下几点:

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/

相关文章:

c++ - integer_sequence 和默认参数值

c++ - 通过 Box2d 中的 NSNotificationCenter 发送 C++ 类对象。错误 : No viable conversion from 'MyContact' to 'id'

c++ - “is not required” ==未定义行为?

c++ - 使用应用程序的 Windows API commctrl.h 无法在没有 Platform SDK 的计算机上运行

asp.net-mvc-3 - MVC3 Html.EditorFor 没有在我的 View 中渲染任何东西

c++ - 这种 rebind_alloc 的使用是错误的吗?

c++ - 可能具有长度为零的数组的模板化数据类型

c - Makefile - 对函数的 undefined reference

gcc make - 正确整理制作目标文件的顺序

c++ - 为什么 lambda 在 clang 而不是 gcc 上崩溃?