Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 打破C+的变化+;20或重载与非布尔返回值的相等比较时clang trunk/gcc trunk中的回归?_C++_Language Lawyer_Eigen_Eigen3_C++20 - Fatal编程技术网

C++ 打破C+的变化+;20或重载与非布尔返回值的相等比较时clang trunk/gcc trunk中的回归?

C++ 打破C+的变化+;20或重载与非布尔返回值的相等比较时clang trunk/gcc trunk中的回归?,c++,language-lawyer,eigen,eigen3,c++20,C++,Language Lawyer,Eigen,Eigen3,C++20,下面的代码在c++17模式下使用铿锵trunk可以很好地编译,但在c++2a(即将推出的c++20)模式下会中断: 它还可以使用gcc主干或clang-9.0.0编译: 发出叮当声的主干和-std=c++2a出现错误: <source>:12:19: error: use of overloaded operator '!=' is ambiguous (with operand types 'Foo' and 'Foo') Meta res = (f != g);

下面的代码在c++17模式下使用铿锵trunk可以很好地编译,但在c++2a(即将推出的c++20)模式下会中断:

它还可以使用gcc主干或clang-9.0.0编译:

发出叮当声的主干和
-std=c++2a
出现错误:

<source>:12:19: error: use of overloaded operator '!=' is ambiguous (with operand types 'Foo' and 'Foo')
    Meta res = (f != g);
                ~ ^  ~
<source>:6:10: note: candidate function
    Meta operator!=(const Foo&) {return Meta{};}
         ^
<source>:5:10: note: candidate function
    Meta operator==(const Foo&) {return Meta{};}
         ^
<source>:5:10: note: candidate function (with reversed parameter order)
与我上面的示例相反,这甚至在gcc主干中失败:。 我还没有设法将其简化为一个非本征示例,它在clang trunk和gcc trunk中都失败(顶部的示例非常简化)

相关问题报告:


我的实际问题是:这实际上是C++20中的一个突破性更改(是否有可能重载比较运算符以返回元对象),还是更可能是clang/gcc中的回归?

[over.match.best]/2列出了集合中有效重载的优先级。第节告诉我们,
F1
优于
F2
if(除其他外):

F2
是重写的候选者([over.match.oper]),而
F1
不是


那里的示例显示了一个显式的
操作符Yes,代码实际上在C++20中中断

表达式
Foo{}=Foo{}
在C++20中有三个候选者(而在C++17中只有一个):

这来自于中新重写的候选规则。所有这些候选者都是可行的,因为我们的
Foo
参数不是
const
。为了找到最佳可行的候选人,我们必须通过决胜局

最佳可行功能的相关规则如下:

根据这些定义,一个可行函数
F1
被定义为比另一个可行函数
F2
更好的函数,如果对于所有参数
i
ICSi(F1)
不是比
ICSi(F2)
更糟糕的转换序列,则

  • […这个例子中有很多不相关的案例…]或者,如果不是那样,那么
  • F2是重写的候选者([over.match.oper]),而F1不是
  • F1和F2是重写候选,F2是参数顺序相反的合成候选,F1不是
#2
#3
是重写候选项,
#3
的参数顺序相反,而
#1
不重写。但是,为了达到这一点,我们需要首先通过这个初始条件:对于所有的参数,转换序列并不更差

#1
优于
#2
,因为所有的转换序列都是相同的(很小,因为函数参数是相同的),并且
#2
是重写候选,而
#1
不是

但是。。。在第一种情况下,两对
#1
/
#3
#2
/
#3
卡滞。在这两种情况下,第一个参数对于
#1
/
#2
具有更好的转换顺序,而第二个参数对于
#3
具有更好的转换顺序(即
常量的参数必须经过额外的
常量
限定,因此其转换顺序更差)。这种
const
触发器使我们无法选择其中一种

因此,整个重载解决方案是不明确的

据我所知,这只适用于返回类型为
bool
的情况

那是不对的。我们无条件地考虑改写和颠倒的候选人。我们的规则是:

如果重写的
运算符==
候选者是通过运算符
@
的重载解析选择的,则其返回类型应为cv
bool

P:那就是,我们仍然考虑这些候选人。但是,如果最佳可行的候选者是一个返回的
操作符==
,比如说,
Meta
,那么结果基本上与该候选者被删除时相同

我们不希望处于过载解决方案必须考虑返回类型的状态。在任何情况下,这里的代码返回
Meta
这一事实都是无关紧要的——如果它返回
bool
,问题也会存在


谢天谢地,这里的修复很容易:

struct Foo {
    Meta operator==(const Foo&) const;
    Meta operator!=(const Foo&) const;
    //                         ^^^^^^
};

一旦您使用两个比较运算符
const
,就不再有歧义了。所有的参数都是相同的,因此所有的转换序列基本上是相同的<代码>#1
现在通过不重写而击败
#3
#2
现在通过不反转而击败
#3
,这使得
#1
成为最佳可行的候选。与我们在C++17中得到的结果相同,只需再多走几步即可实现。

本征问题似乎归结为以下几点:

使用标量=double;
模板
结构基{
友元内联整数运算符==(常量标量&,常量派生&){return 1;}
int运算符!=(常量标量&)常量;
};
结构X:Base{};
int main(){
X{}!=0.0;
}
该表达式的两个候选项是

  • 运算符==(常量标量&,常量派生&)重写的候选项
  • Base::operator=(常数标量和)常数
  • 根据,作为
    操作员=未通过using声明导入到
    X
    的范围中,#2的隐式对象参数的类型为
    const Base&
    。因此,#1对于该参数具有更好的隐式转换序列(精确匹配,而不是派生到基转换)。选择#1会导致程序格式错误

    可能的修复方法:

    • 使用Base::operator!=添加
      到衍生的
      ,或
    • 运算符==
      更改为采用
      常量基&
      而不是
      常量派生&

    我们的Goopax头文件也有类似的问题。使用clang-10和-std=c++2a编译以下内容会产生编译器错误

    template<typename T> class gpu_type;
    
    using gpu_bool     = gpu_type<bool>;
    using gpu_int      = gpu_type<int>;
    
    template<typename T>
    class gpu_type
    {
      friend inline gpu_bool operator==(T a, const gpu_type& b);
      friend inline gpu_bool operator!=(T a, const gpu_type& b);
    };
    
    int main()
    {
      gpu_int a;
      gpu_bool b = (a == 0);
    }
    
    模板类gpu\u类型;
    乌辛
    
    Meta operator!=(Foo& /*this*/, const Foo&); // #1
    Meta operator==(Foo& /*this*/, const Foo&); // #2
    Meta operator==(const Foo&, Foo& /*this*/); // #3 - which is #2 reversed
    
    struct Foo {
        Meta operator==(const Foo&) const;
        Meta operator!=(const Foo&) const;
        //                         ^^^^^^
    };
    
    template<typename T> class gpu_type;
    
    using gpu_bool     = gpu_type<bool>;
    using gpu_int      = gpu_type<int>;
    
    template<typename T>
    class gpu_type
    {
      friend inline gpu_bool operator==(T a, const gpu_type& b);
      friend inline gpu_bool operator!=(T a, const gpu_type& b);
    };
    
    int main()
    {
      gpu_int a;
      gpu_bool b = (a == 0);
    }
    
    template<typename T>
    class gpu_type
    {
      ...
      friend inline gpu_bool operator==(const gpu_type& b, T a);
      friend inline gpu_bool operator!=(const gpu_type& b, T a);
    };