考虑以下静态断言:
static_assert(std::is_convertible_v<int const&, int const>);
static_assert(std::is_convertible_v<int const, int>);
static_assert(std::is_convertible_v<int, int &&>);
static_assert(std::is_convertible_v<int const&, int &&>);
以上三个断言都通过了,但是最后一个断言失败了。
这意味着C ++中的类型可转换性通常不是可传递的,我认为这非常违反直觉。
我在标准和cppreference网站上进行了搜索,以发现任何证据表明这是预期的行为,但是到目前为止,我还没有成功。
有趣的是,对于左值引用,一切都很好,因为std::is_convertible_v<int, int&>
为假。我也希望能得到右值引用。
我认为它与is_convertible
的定义有关。在定义中,To
自变量作为虚函数的返回类型出现。据我了解,任何类型的新值都是临时的,因此可以转换为右值引用。因此std::is_convertible_v<T, T&&>
适用于任何类型的T
。
更具体地说,我问以下问题:
is_convertible
是否真的抓住了可兑换的直觉?is_convertible
理解为一种二元关系,那它不应该是一个预定单,即和物吗?为什么不呢?直觉上,恕我直言,可转换性是指:每当需要类型To
时,您也可以使用类型From
。这将意味着可传递性。
尤其是,T
不应转换为T&&
,因为在需要T
的地方,您不能使用T&&
(您可能无法从{{1} },但是您可以从T
移出。
我在这里遇到严重问题吗?
答案 0 :(得分:3)
直觉上,恕我直言,可兑换性是指:每当需要输入To时,您也可以使用From ....类型。
这就是它的意思。
...这将意味着可传递性。
不,这是不正确的。并非每个二进制关系都必须是可传递的。从cppreferene开始隐式转换:
隐式转换序列按以下顺序组成:
1)零或一个标准转换序列;
2)零或一次用户定义的转换;
3)零个或一个标准转换序列。
在考虑构造函数或用户定义的参数时 转换功能,仅允许一个标准转换序列 (否则,可以有效地链接用户定义的转化)。 从一种内置类型转换为另一种内置类型时,仅 允许一个标准的转换顺序。
确切的规则涉及其中,但是考虑“零或一个用户定义的转换”;因此,当用户定义了从Foo
到Bar
以及从Bar
到Baz
的转换时,这并不一定意味着Foo
会转换为{{ 1}}!
并不是Baz
拥有可转换的怪异概念,但是C ++中关于可转换内容的规则并不是一开始就可以传递的。
答案 1 :(得分:1)
这意味着C ++中的类型可转换性通常不是可传递的,我认为这非常违反直觉。
通常来说,您不想将const T&
转换为T&&
。这可能会带来灾难性的影响。您可能希望发生编译器错误,以免意外std::move
从调用者那里获取数据(或者创建一个看起来像没有副本的 一样的意外副本)
现在,标准对此要说些什么? http://localhost..
标准转换顺序是以下顺序的标准转换顺序:
-下列一组中的零或一转换:左值到右值转换,数组到指针转换以及函数到指针转换。
-以下集合中的零个或一个转换:整数提升,浮点提升,整数转换,浮点转换,浮点积分转换,指针转换,指针到成员转换以及布尔转换。
-零或一个函数指针转换。
-零或一次资格转换。
因此,我们可以通过[conv]将int const&
隐式转换为int
(在非类类型上,它将删除cv资格)。
我们还可以通过Identity会话将int
隐式转换为int&&
(无需转换,因为我们可以将prvalue进行引用绑定到rvalue引用)。
但是我们不能将int const&
隐式转换为int&&
,因为这需要
int const&
到int
,然后int
到int const&
这是因为根据lvalue-to-rvalue conversion,我们无法将Identity转换与其他转换混合使用:
标准转换序列要么是身份转换本身(即没有转换),要么由其他四个类别中的一到三个转换组成。
(类别由[over.ics.scs]定义)