编译器之间的重载分辨率不同 [英] Overload Resolution differs between compilers

查看:68
本文介绍了编译器之间的重载分辨率不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经构建了以下最小的问题示例:

I have constructed the following minimal example of my problem:

#include <iostream>

struct Foo {
  Foo() {
    std::cout << "default" << std::endl;
  }
  Foo(Foo& f2) {
    std::cout << "non-const" << std::endl;
  }
  Foo(const Foo& f2) {
    std::cout << "const" << std::endl;
  }
};

int main() {
        std::pair<Foo, int> foop0(Foo(), 1);
        std::cout << std::endl;
        std::pair<const Foo, int>foop1(foop0);
}

在我的Ubuntu机器上g ++(Ubuntu 7.5.0-3ubuntu1〜18.04)7.5 .0将打印以下内容:

On my Ubuntu machine g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 will print out the following:

$ g++ -std=c++14 test.cpp -o test && ./test
default
const

const

但是,在我的Mac上的Apple clang(版本11.0.3(clang-1103.0.32.62)
目标:x86_64-apple-darwin19.4.0)将打印:

However, Apple clang (version 11.0.3 (clang-1103.0.32.62) Target: x86_64-apple-darwin19.4.0) on my Mac will print:

$ g++ -std=c++14 test.cpp -o test && ./test
default
const

non-const

但是,情况变得更糟:如果我将最后一行更改为

However, it gets worse: If i change the last line to

std::pair<Foo, int>foop1(foop0);
          ^ removed const

两个编译器都将给出第一个输出。

both compilers will give the first output.

为什么会这样?

编辑:根据 cppreference ,应按g ++的原样选择std :: pair的ctor。仍然没有在这里解释c的怪异行为。

I have now understood why, according to cppreference, std::pair's ctors should be selected as they are by g++. Still doesn't explain clang's weird behaviour here. A non-conforming implementation maybe?

推荐答案

就像已经说过的那样,可能是 std :: pair的实现。 两者都不同。我编写了两个非常相似的实现对,它们表现出完全不同的行为,即使不改变该对的类型也是如此: godbolt

Like already said, probably the implementations of std::pair for both of them differ. I wrote two very similar implementations of a pair that exhibit exactly your differing behaviors, even without changing the type of the pair: godbolt

#include <iostream>

struct T {
    T() { 
        std::cerr << "default\n";
    }

    T(T&) {
        std::cerr << "non-const\n";
    }

    T(const T&) {
        std::cerr << "const\n";
    }

};

// Comment or uncomment to change the behavior.
//#define MAC

template<class First, class Second>
struct pair {
    First first;
    Second second;

    pair(const First& f, const Second& s) : first(f), second(s) {
    }

#ifdef MAC

    pair(pair<First, Second>& p) : first(p.first), second(p.second) {
        std::cerr << "copy Mac-Like\n";
    }

#else

    pair( pair<First, Second>& p) : pair(p.first, p.second) {
        std::cerr << "copy Ubuntu-Like\n";
    }
#endif

};

int main() {
    T t;
    pair<T, int> u1(t, 0);

    pair<T, int> u2(u1);
}

当然,mac和ubuntu上的对都写得更合理(和符合标准),并让标准副本构造函数使用const引用(这就是为什么他们两个都使用const变体的原因)。但是我猜想它们从具有不同但可转换类型的对中处理复制构造函数。要找出完全不同的地方,需要比较两个系统上的stl实现。

Of course, the pairs on mac and ubuntu are both written more reasonably (and standard-conforming) and have the standard-copy-constructor taking a const-reference (which is the reason for both of them using the const variant then). But I guess they handle the copy constructors from pairs with differing but convertible types differently. Finding out what exactly is different would require to compare the stl implementations on both systems.

Ubuntu变体对我来说似乎很清楚,该对仅由构造函数中的const引用从一对可转换类型中获取。如果在构造链的任何位置都具有const,则最终会得到 T 的const copy构造函数。

The Ubuntu variant seems pretty clear to me, there the pair is just taken by const reference in the constructor from a pair of convertible types. When you have a const at any point of your construction chain you will end up with the const copy constructor of T.

我发现Mac行为有点怪异,因为它们必须通过值或非const引用来获取对(实际上,您不应该具有复制构造函数以非const引用为例,为什么要更改它复制的内容呢?这似乎是 std :: auto_ptr 级的怪异值)。也许他们(试图变得)对某种重视价值然后行动的东西很聪明。

I find the Mac behavior a bit weird since they have to either take the pair by value or by non-const reference (and really, you should not have a copy constructor taking by non-const reference, why should it ever change the thing it copies? This seems like std::auto_ptr-level weirdness). Maybe they are (trying to be) clever with some kind of "take it by value and then move" thing.

但是我认为这是不符合要求的,因为对构造函数应该通过const-reference或rvalue-reference接受所有其他对。由于我们正在复制,因此它应该使用copy构造函数,采用const引用,因此也具有对 pair.first 的const引用,并以此获取其const copy构造函数。

But I think this is non-conforming, since the pair constructor should take all other pairs by const-reference or by rvalue-reference. Since we are copying, it should use the copy constructor, taking a const reference and hence also have a const reference to the pair.first and by this taking its const copy constructor.

这篇关于编译器之间的重载分辨率不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆