【问题标题】:C++: MSC not resolving a template operator (gcc and clang ok)C++:MSC 不解析模板运算符(gcc 和 clang ok)
【发布时间】:2021-07-06 21:58:43
【问题描述】:

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

我怀疑这是 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++ templates visual-c++ sfinae compiler-bug


    【解决方案1】:

    如果我们是迂腐的,在 C++17 中,非类型模板参数不能具有类型 void*,请参阅 [temp.param]/4.2

    非类型模板参数应具有以下类型之一(可选 cv 限定):
    . . .
    — 指向对象的指针或指向函数的指针,
    . . .

    (注意:在 C++20 中一直是rectified)。

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

    要获得更便携的代码,请使用基于int 而不是void* 的SFINAE:

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

    这在 MSVC 16.9 中编译正常。

    【讨论】:

    • 太好了,谢谢。我从未在 enable_if 和其他类似的元编程模板中使用显式类型。到目前为止,void* = nullptr 已被接受。这个线程中的具体组合显然是MSVC++的一个bug。但是您的解决方案显然更符合 C++11(我使用的级别)并且没有 MSVC++ 错误。
    猜你喜欢
    • 2014-07-12
    • 2014-11-13
    • 2018-03-09
    • 1970-01-01
    • 1970-01-01
    • 2012-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多