T declval() 代替 T && declval() 表示common_type

T declval() instead of T && declval() for common_type

本文关键字:declval type 代替 表示 common      更新时间:2023-10-16

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

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

然后是当前的:

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

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

使用(1)common_type的行为更接近三元运算符的行为(但不使用std::decay_t),而不是使用(2)时的行为:

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

活生生的例子。

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

参考文章说:

对于非专用 std::common_type,确定每对 T1、T2 之间的公共类型的规则正是在未计算上下文中确定三元条件运算符返回类型的规则,其中任意第一个参数为 bool 类型,xvalues of type T1 and T2 (since C++17) std::declval<T1>() and std::declval<T2>() (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 注释中有一些关于std::common_type问题的澄清,但这只是当前问题的背景信息。

优点

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

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

当然,差异是common_type<int, int>最终是int&&,然后你需要添加decay,使common_type<int&, int&> int - 这也没有意义。这里只是没有胜利。

<小时 />

最终,我认为我们只需要一些语言功能,在未经评估的上下文中,"给我一些 T 型的东西",适用于任何T这确实为您提供了T(而不是T&&)。