C ++列表初始化允许多个用户定义的转换 [英] C++ list initialization allows multiple user-defined conversions

查看:97
本文介绍了C ++列表初始化允许多个用户定义的转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读此答案,其中包含以下示例:

struct R {};
struct S { S(R); };
struct T { 
    T(const T &); //1 
    T(S);         //2
};
void f(T);
void g(R r) {
    f({r});
}

答案与[over.best.ics]/4的旧版本有关,该旧版本当时看起来像解决方案

您的观察是正确的.即使没有强调的部分,该示例也格式正确,但是原因有些不同.

而且我在标准中找不到任何东西可以在列表初始化的转换中进行多个用户定义的转换.

实际上,[over.best.ics]/4正是禁止多于一个用户定义的转换的规则.考虑到(1)被调用,那么我们必须用r复制并初始化类型为T的临时对象,该对象属于或" [over.match.copy],[over.match.conv]或[在所有情况下都是[over.match.ref]"部分,因此禁止用户定义的转换(r -> const T&r -> S).结果,我们无法为(1)形成隐式转换序列,因此(2)获胜.

请注意,由于问题1758 ,并由于this answer, which has the following example:

struct R {};
struct S { S(R); };
struct T { 
    T(const T &); //1 
    T(S);         //2
};
void f(T);
void g(R r) {
    f({r});
}

The answer is related to an old version of [over.best.ics]/4, which back then looked like this:

However, when considering the argument of a constructor or user-defined conversion function that is a candidate by [over.match.ctor] when invoked for the copying/moving of the temporary in the second step of a class copy-initialization, by [over.match.list] when passing the initializer list as a single argument or when the initializer list has exactly one element and a conversion to some class X or reference to (possibly cv-qualified) X is considered for the first parameter of a constructor of X, or by [over.match.copy], [over.match.conv], or [over.match.ref] in all cases, only standard conversion sequences and ellipsis conversion sequences are considered.

In the answer it is said that without the highlighted part in the above quote, f({r}) would be ambiguous, because it could use either the first constructor of T (1) or the second constructor (2).

However, as much as I tried, I cannot see how the first constructor (1) is an option. f({r}) results in a copy-list-initialization of T from {r}. If the first constructor is used, the standard allows a conversion from r to the type of the parameter of the constructor. However, just one conversion is not enough, as one would have to go R --> S (using the converting constructor of S) and then S --> T (using the converting constructor of T (2)). And I cannot find anything in the standard that allows more than one user-defined conversion in the cast of list initialization.

I may be missing something. I would appreciate if someone pointed out where I am mistaken, or if I am not, I would like to know what is the purpose of the highlighted section in the quote from the standard.

The current version of the quoted paragraph requires that the only element of the initializer list be an initializer list itself, which would make sense in the example above, if instead of f({r}) there was f({{r}}). In that case, the explanation would be correct.

Thank you.

解决方案

Your observation is correct. The example is well-formed even without the emphasized part, but the reason is a bit different.

And I cannot find anything in the standard that allows more than one user-defined conversion in the cast of list initialization.

In fact, [over.best.ics]/4 is exactly the rule that forbids more than one user-defined conversion. Consider (1) is called, then we must copy-initialize a temporary object of type T with r, which falls into the "or by [over.match.copy], [over.match.conv], or [over.match.ref] in all cases" part, thus user-defined conversions (r -> const T& and r -> S) are forbidden. As a result, we cannot form an implicit conversion sequence for (1), thus (2) wins.

Note the emphasized part was ever deleted due to issue 1758, and came back again with the constraint "the initializer list has exactly one element that is itself an initializer list" due to issue 2076.

这篇关于C ++列表初始化允许多个用户定义的转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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