【问题标题】:Gcc fails with "call of overload is ambignuous" while clang does notGcc 因“重载调用不明确”而失败,而 clang 则没有
【发布时间】:2016-08-08 13:24:32
【问题描述】:

我有以下代码:

#include <experimental/string_view>

struct b_symbol {
    template <typename T>
     explicit b_symbol(T&& symbol)
        : symbol(std::forward<T>(symbol)) {
    }

    std::experimental::string_view symbol;
};

struct b_utf8 {
    template <typename T>
    explicit b_utf8(T&& value)
        : value(std::forward<T>(value)) {
    }

    std::experimental::string_view value;

};

struct value {
    explicit value(b_utf8) {}
    explicit value(b_symbol) {}

};

int main() {
    value v({b_utf8("test")});
}

您可以在godbolt 上试用。

如果我用 clang (3.8.0) 编译它:
clang++ oload.cpp -std=c++1y
一切正常。

如果我用 gcc (6.1.1 20160602) 编译它
g++ oload.cpp -std=c++1y
我明白了:

oload.cpp: In function ‘int main()’:
oload.cpp:30:29: error: call of overloaded ‘value(<brace-enclosed initializer list>)’ is ambiguous
     value v({b_utf8("test")});
                             ^
oload.cpp:25:14: note: candidate: value::value(b_symbol)
     explicit value(b_symbol) {}
              ^~~~~
oload.cpp:24:14: note: candidate: value::value(b_utf8)
     explicit value(b_utf8) {}
              ^~~~~
oload.cpp:23:8: note: candidate: constexpr value::value(const value&)
 struct value {
        ^~~~~
oload.cpp:23:8: note: candidate: constexpr value::value(value&&)

为什么会有这种差异?
gcc 的行为是否正确?

编辑: 正如 slavanap 在他的回答中指出的那样,可以通过删除呼叫站点上的花括号来规避该错误。尽管如此,我还是想知道为什么编译器的行为不同。

【问题讨论】:

  • 好吧...“std::experimental”

标签: c++ gcc clang


【解决方案1】:

您正在将初始化列表传递给明确采用 b_utf8 或 b_symbol 的构造函数,两者都不正确。

如果您不想使用隐式强制类型转换,则必须定义一个接受初始化列表的构造函数。

我认为这正在为 C++17 进行更改,届时您将被允许以 clang 的方式进行更改。

编辑: 有意思

struct  b_utf8 {

  b_utf8() = default;
  //b_utf8(){}
};

struct value {
  explicit value(b_utf8) {}
};

int main() {
    value v({b_utf8()});
}

编译但是

struct  b_utf8 {

  //b_utf8() = default;
  b_utf8(){}
};

struct value {
  explicit value(b_utf8) {}
};

int main() {
    value v({b_utf8()});
}

重载决议失败。我不确定为什么,据我所知,重载决议应该在这两种情况下表现相同。

【讨论】:

  • 关于初始化列表只能传递给构造函数以initializer_list 的建议是错误的,clang 和 GCC 的行为都表明它是错误的。
  • 我没这么说。
  • =default 对隐式声明的限制更大,请参阅this question
【解决方案2】:

在错误中显示&lt;brace-enclosed initializer list&gt;

    // Why not just try to call 
    value v(b_utf8("test"));
    // instead
    value v({b_utf8("test")});
    // ?

【讨论】:

  • 是的,我知道,这修复了错误。但我仍然想知道为什么编译器的行为不同。
  • 我想知道你为什么要在大括号中传递它。它可能会提供关于编译器对experimental 类的实现或从/到initializer_list 的转换的有趣轶事,但有任何实际理由这样做吗?
  • @underscore_d 在这种特殊情况下,我没有理由在花括号中传递它,这是一个错误。
  • 酷。好吧,我有兴趣看看答案是什么!我会避免猜测,因为我的大脑无法处理所有可能发生或可能不会发生的转换。 :s
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-11
  • 1970-01-01
  • 1970-01-01
  • 2019-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多