【问题标题】:T declval() instead of T && declval() for common_typeT declval() 而不是 T && declval() for common_type
【发布时间】:2016-06-02 05:49:19
【问题描述】:

使用std::declval在表单中声明不是更好吗:

template< class T > T declval(); // (1)

然后是当前的:

template< class T > T && declval(); // (2)

对于std::common_type(可能仅出于当前目的使用不同的名称)?

使用(1)common_type 的行为比使用@987654331 时的行为更接近三元运算符(但不使用 std::decay_t)的行为@:

template< typename T >
T declval();

template <class ...T> struct common_type;

template< class... T >
using common_type_t = typename common_type<T...>::type;

template <class T>
struct common_type<T> {
    typedef T type;
};

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

template <class T, class U, class... V>
struct common_type<T, U, V...> {
    typedef common_type_t<common_type_t<T, U>, V...> type;
};

#include <type_traits>
#include <utility>

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunevaluated-expression"
int
main()
{
    int i{};
    static_assert(std::is_same< int &, decltype((i)) >{});
    static_assert(std::is_same< int  , std::common_type_t< decltype((i)), decltype((i)) > >{}); 
    static_assert(std::is_same< int &, decltype(true ? i : i) >{});
    static_assert(std::is_same< int &, common_type_t< decltype((i)), decltype((i)) > >{});

    int && k{};
    static_assert(std::is_same< int &&, decltype(k) >{});
    static_assert(std::is_same< int   , std::common_type_t< decltype(k), decltype(k) > >{}); 
    static_assert(std::is_same< int &&, decltype(true ? std::move(k) : std::move(k)) >{}); 
    static_assert(std::is_same< int &&, common_type_t< decltype(k), decltype(k) > >{});
    return 0;
}
#pragma clang diagnostic pop

Live example.

这种方法有什么缺点?对 (1) 中的 decltype() 上下文类型 T 是否应该是可构造的(完全是,即应该至少有一个构造函数)和/或可破坏的?

Reference article说:

对于非特化的 std::common_type,确定每对 T1、T2 之间的公共类型的规则恰好是确定未计算上下文中的三元条件运算符的返回类型的规则,具有任意 bool 类型的第一个参数并以 xvalues of type T1 and T2 (since C++17) std::declval&lt;T1&gt;() and std::declval&lt;T2&gt;() (until C++17) 作为第二个和第三个操作数。 The common type is the result of std::decay applied to the type of the ternary conditional (since C++14).

我认为很可能最后一句话 (emphasized) 不应该只是 since C++14 而是 until C++17 是公平的。否则即使在 C++17 之后引用的第一句也不成立,并且会出现一些缺陷。

should-stdcommon-type-use-stddecay cmets 中有一些关于std::common_type 问题的说明,但这只是当前问题的背景信息。

【问题讨论】:

  • 首先,如果类型具有已删除的析构函数或无法从函数返回(例如,抽象类型、数组类型、函数类型),则会中断。
  • @T.C.我认为对于 std::common_type 的当前默认实现中的这些类型 三元运算符 也没有意义,但专业化确实如此。
  • @T.C.真的,我们只需要一种语言功能,即“给我一个T 类型的表达式”
  • FWIW 我一直在使用我自己的common_type 一段时间,因为我同意这是一个更明智的规范。话虽如此,对于为什么它更好,我没有论据,所以我无法真正回答你的问题。

标签: c++ c++11 c++14 typetraits c++17


【解决方案1】:

优点:

template <class T> T&& declval();

它适用于any 类型T,而简单地返回T 不适用于不可返回的类型(例如函数、数组)和不可销毁的类型(例如私有/受保护/删除的析构函数,抽象基类)。

当然,缺点是common_type&lt;int, int&gt; 最终成为int&amp;&amp;,然后您需要添加decay,这使得common_type&lt;int&amp;, int&amp;&gt; 成为int——这也没有意义。这里没有胜利。


最终,我认为我们只需要一些语言功能,在未评估的上下文中,“给我一些T 类型的东西”,适用于任何T真的给你T(而不是 T&amp;&amp;)。

【讨论】:

  • "给我一些 T 型的东西" 这正是 declval 所做的。如果你给它T&amp;,它会给你一个T类型的左值,如果你给它T或@,它会给你一个T类型的xvalue(模void(prvalue)和函数类型(lvalue)) 987654339@。如果你想使用纯右值,它有它自己的缺陷——除了我之前给出的例子之外,它会丢弃非类类型上的 cv 限定符。
猜你喜欢
  • 1970-01-01
  • 2013-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-03
  • 1970-01-01
  • 2017-12-31
  • 1970-01-01
相关资源
最近更新 更多