std::common_type 应该使用 std::decay 吗?

Posted

技术标签:

【中文标题】std::common_type 应该使用 std::decay 吗?【英文标题】:should std::common_type use std::decay? 【发布时间】:2014-03-25 09:50:49 【问题描述】:

给定类型A,B,我关心std::common_type<A,B> 的确切定义,忽略任意类型A... 的可变参数情况std::common_type<A...>。所以让

using T = decltype(true ? std::declval<A>() : std::declval<B>());
using C = std::common_type<A,B>;

现在,根据一些消息来源,我发现了以下关系(为简洁起见,跳过typename):

cppreference.com:C::type = std::decay&lt;T&gt;::type

cplusplus.com:C::type = T

GCC 4.8.1 &lt;type_traits&gt; 实现:C::type = std::decay&lt;T&gt;::type 如果T 有效,否则C 不包含::type 成员(“SFINAE-friendly”)

李>

Clang 3.3 &lt;type_traits&gt; 实现:C::type = std::remove_reference&lt;T&gt;::type

我发现 GCC 的“SFINAE 友好”版本是一个小细节,而 std::remove_referencestd::decay 实际上只在内置数组和函数以及 cv 限定方面有所不同,对此我也不太关心.所以我的问题是

应该是decay&lt;T&gt;::type 还是只是T?使用decay&lt;T&gt;::type 的理由是什么?仅代表结果A() + B() 例如算术表达式?

例如,我尝试了一下,发现在“just T”定义的情况下,我们有

common_type<int&,int&> = int&
common_type<int&,long&> = long

也就是说,如果类型相等,则维护一个左值引用。这反映了这样一个事实:

int a, b;
(true ? a : b) = 0;

有效,而

int a;
long b;
(true ? a : b) = 0;

不是。这种“如果类型相等则允许赋值”的语义正是我在一个应用程序中所需要的,我倾向于认为common_typedecay 应该是两个独立的步骤。我应该只使用我自己的定义吗?

【问题讨论】:

remove_referencedecay 在引用类型的 cv 限定方面也不同; std::declval&lt;A&gt; 返回一个右值引用。 T 是旧的 (C++11),decay&lt;T&gt; 是新的 (C++1y),可能存在与此相关的缺陷。让我看看.. 这里是:open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#2141 是的,如果您需要一个可以将相同的左值引用类型统一为静态引用的版本,最好自己编写。 是的,它确实变得复杂,尤其是foo。例如。给定foo f;,你可以说++f;,但不能说f = 0;。除了这种情况,我更倾向于只删除右值引用(由declval 引起)并保持 cv-qualification 完好无损。无论如何,我会看看它如何与我的应用程序配合使用。 【参考方案1】:

std::common_type 应该使用 std::decay 吗?

是的,请参阅Library Working Group Defect #2141。

短版(长版,见上面的链接):

declval&lt;A&gt;() 返回一个A&amp;&amp;

common_type 是通过declval,n3337 指定的:

template <class T, class U>
struct common_type<T, U> 
    typedef decltype(true ? declval<T>() : declval<U>()) type;
;

common_type&lt;int, int&gt;::type 因此产生int&amp;&amp;,这是出乎意料的

建议的解决方案是添加decay

template <class T, class U>
struct common_type<T, U> 
    typedef decay_t < decltype(true ? declval<T>() : declval<U>()) > type;
;

common_type&lt;int, int&gt;::type 现在产生int

【讨论】:

嗯...这确实显示了我们最终如何使用decay,所以它回答了这个问题,非常感谢。然而太糟糕了,我现在必须使用我自己的定义......是的,&lt;int,int&gt; 应该给int 而不是int&amp;&amp;,但&lt;int&amp;,int&amp;&gt; 应该给我int&amp;。所以只有declval添加的额外&amp;&amp;应该被删除。 @iavr LWG 页面上的讨论包含 common_type 的用户不希望得到引用类型作为结果” 不确定用户是谁 是,但是。 好吧,我肯定不是 :-) 呸,如果我提供参考资料,我希望得到参考资料,而且我是common_type 的用户。如果我想实现多参数链式? 的等价物,common_type 现在的行为根本不同,因为common_type 是唯一一个人们期望像std::chrono 和其他扩展这样专业化的地方,人们可以不再实现多参数链式? 我刚到这里是因为我希望 common_type 返回一个 int&。它返回一个 int,我的代码静默编译,测试失败。已经调试了一段时间......幸运的是我有一个测试。

以上是关于std::common_type 应该使用 std::decay 吗?的主要内容,如果未能解决你的问题,请参考以下文章

我啥时候应该使用 std::any

在啥情况下你应该更喜欢使用 std::copy 写入 cout?

我们啥时候应该使用 std::enable_shared_from_this

我应该使用 std::remove 从列表中删除元素吗?

移动局部变量时应该使用 std::move 吗? [复制]

使用 std::map 时,我应该为键类型重载 operator== 吗?