“歧义转换顺序”-此概念的目的是什么?

AnT*_*AnT 6 c++ conversion-operator language-lawyer overload-resolution implicit-conversion

在N4659中16.3.3.1隐式转换序列

10如果存在几个不同的转换序列,每个转换序列都将自变量转换为参数类型,则与参数关联的隐式转换序列被定义为唯一的转换序列,称为歧义转换序列。为了对16.3.3.2中所述的隐式转换序列进行排名,歧义转换序列被视为与其他任何用户定义的转换序列都没有区别的用户定义的转换序列[注意:此规则可防止函数变为非-viable,因为其参数之一的转换顺序不明确。]如果选择使用歧义转换顺序的函数作为最佳可行函数,则该调用将格式错误,因为该调用中参数之一的转换是模棱两可的。

(当前草案的相应部分为12.3.3.1

该规则的预期目的是什么,以及引入的歧义转换序列的概念是什么?

文本中提供的注释指出,此规则的目的是“防止功能由于其参数之一的转换顺序不明确而变得不可行 ”。嗯...这实际上是指什么?可行功能的概念在文档的前面部分中定义。它根本不取决于转换的歧义性(每个参数的转换必须存在,但不必明确)。而且似乎没有提供可行的功能以某种方式在以后“变得不可行”的规定(既不是出于某种模棱两可,也不是因为其他原因)。列举了可行的功能,它们相互竞争,成为“最佳”如果有一个“获胜者”,则解决方案成功。在此过程中的任何时候,可行的功能都可能(或需要)变成不可行的功能。

上述段落中提供的示例不是很有启发性(即尚不清楚上述规则在该示例中扮演什么角色)。


这个简单的例子最初引发了这个问题

struct S
{
  operator int() const { return 0; };
  operator long() const { return 0; };
};

void foo(int) {}

int main()
{
  S s;
  foo(s);
}
Run Code Online (Sandbox Code Playgroud)

让我们在这里机械地应用上述规则。foo是可行的功能。从参数类型S到参数类型有两个隐式转换序列intS -> intS -> long -> int。这意味着,根据上述规则,我们必须将它们“打包”成单个模糊的转换序列。然后我们得出结论,这foo最好的可行功能。然后我们发现它使用了我们不明确的转换序列。因此,根据上述规则,代码格式错误。

这似乎没有任何意义。这里的自然期望是,S -> int应该选择转化,因为它的排名高于S -> long -> int转化。我知道的所有编译器都遵循“自然的”过载解析。

那么,我误会什么呢?

Yak*_*ont 3

为了可行,必须有一个implicit conversion sequence

该标准可能允许多个隐式转换序列,但这可能会使用于确定选择哪个重载的措辞变得更加复杂。

因此,该标准最终为每个参数的每个实参定义了一个且恰好一个隐式转换序列。在存在歧义的情况下,它使用的是歧义转换序列

一旦完成此操作,它就不再需要处理一个参数到一个参数的多个转换序列的可能性。

想象一下如果我们用 C++ 编写这个。我们可能有以下几种类型:

namespace conversion_sequences {
  struct standard;
  struct user_defined;
  struct ellipsis;
}
Run Code Online (Sandbox Code Playgroud)

每个里面都有很多东西(这里跳过)。

由于每个转换序列都是上述序列之一,因此我们定义:

  using any_kind = std::variant< standard, user_defined, ellipsis >;
Run Code Online (Sandbox Code Playgroud)

现在,我们遇到了给定参数和参数有多个转换序列的情况。此时我们有两个选择。

我们可以传递using any_kinds = std::vector<any_kind>给定参数、参数对的 a ,并确保处理选择转换序列的所有逻辑都处理该向量......

或者我们可以注意到,对 1 个或多个条目向量的处理从不查看向量中的元素,并且它被完全视为一种user_defined转换序列,直到最后我们生成错误。

存储额外的状态并拥有额外的逻辑是一件痛苦的事情。我们知道我们不需要那个状态,也不需要代码来处理向量。所以我们只定义一个子类型conversion_sequence::user_defined,并且在找到首选重载后的代码会检查所选择的结果重载是否会生成错误。

虽然 C++ 标准并不(总是)在 C++ 中实现,并且措辞不必与其实现具有 1:1 的关系,但编写可靠的标准文档是一种编码,并且存在一些相同的问题。

  • 在阅读较旧的草稿时,这更有意义,其中前一段说“如果找不到将参数转换为参数类型的转换序列,或者转换格式不正确,则无法形成隐式转换序列”。对于“否则格式错误”,我认为他们在尝试在 UCS 中查找用户定义的转换时会出现歧义。在当前的草案中,“否则格式不正确”的部分已经消失。 (3认同)