C++:MSC 不解析模板运算符(gcc 和 clang ok)

标签 c++ templates visual-c++ sfinae compiler-bug

我有一个关于模板类和类型上的 C++ 运算符重载的问题,虽然它被 gcc 和 clang(Linux 和 macOS)接受,但 Microsoft Visual C++ 没有正确解析它。

我怀疑这是 MSVC++ 中的一个错误,但我想在报告错误之前获得专家的建议,以防它可能是相反的(gcc 和 clang 是错误的)。

这个想法是一个必须用某种整数类型实例化的模板类。我们想用任何其他普通整数类型定义加法,两种方式(class + int 和 int + class)。

我可以重现问题的最少代码如下:

#include <type_traits>

template <typename INT, typename std::enable_if<std::is_integral<INT>::value>::type* = nullptr>
class A
{
public:
    template<typename INT2>
    A operator+(INT2 x) const { return A(); }
};

template <typename INT1, typename INT2>
A<INT2> operator+(INT1 x1, A<INT2> x2) { return x2 + x1; }

int main(int argc, char* argv[])
{
    typedef A<int> B;
    B x, y;
    y = x + 1;  // ok everywhere
    y = 1 + x;  // VC++: error C2677: binary '+': no global operator found which takes type 'B' (or there is no acceptable conversion)
}

在原始代码中,到处都有 SFINAE 构造以在必要时强制执行类型检查(包括在两个“+”运算符中)。当他们没有更改编译错误时,我已将它们全部删除。只有 A 类定义中的“enable_if”是必需的。没有它,代码可以用 MSVC++ 编译。

Microsoft Visual Studio 2019,版本 16.9.3。

这里有什么问题? MSVC++ 还是 gcc/clang?

感谢您的建议。

最佳答案

如果我们学究气,在 C++17 中,非类型模板参数不能有 void* 类型,参见 [temp.param]/4.2 :

A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
. . .
— pointer to object or pointer to function,
. . .

(注意:在 C++20 中为 rectified)。

所以它似乎在 MSVC 中出了问题(SFINAE 在 A 本身中成功但导致运算符的查找失败)。 MSVC 尚不完全支持 C++20,但仍值得报告此问题。

为了更便携的代码,使用基于 int 的 SFINAE 而不是 void*:

template <typename INT, typename std::enable_if<std::is_integral<INT>::value, int>::type = 0>
class A {
   . . .

这在 MSVC 16.9 中编译正常。

关于C++:MSC 不解析模板运算符(gcc 和 clang ok),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67047905/

相关文章:

c++ - 使用线程根据起始字符打印出单词

javascript - Rails Assets javascript 模板错误

C++ 在测试成员变量是否等于 NULL 时卡住

c++ - 使用 cout/cin 要求有效输入

c++ - 如何使用 STL 容器来保存基于模板的 shared_ptr?

c++ - 模板不会在 C++ 中推断零长度数组的大小

c++ - Visual Studio 2010 和 windows SDK 7.0a 编译错误

c++ - Win XP x64 上的段错误在 XP x32 上不会发生 - strncpy 问题?怎么修?

c++ - 如何在 msvc 预处理器中打印宏?

c++ - 它是如何解析的:使用大括号的init列表构造未命名的临时文件