使用AppleClang时来自decltype(std :: devlcal <std :: ostream>()<< std :: declval <T>())的奇怪结果

时间:2019-12-09 10:46:22

标签: c++ c++17 decltype

问题

请考虑以下结构:

template<typename T>
struct stream
{
  using type = decltype(
      std::declval<std::ostream>() << std::declval<T>()
    );
};

template<typename T>
using stream_t = typename stream<T>::type;

当对stream_t<T>使用某些内置类型(intfloat,...)时,T的“值”为std::ostream&,如我所料

但是当对std::string使用charint*T或某些可流式伪结构时,类型是右值引用std::ostream&&

std::declval<std::ostream>()(返回std::ostream&&)替换为std::declval<std::ostream&>(由于引用折叠规则,返回std::ostream&,对吗?),返回的类型是预期的std::ostream&。我不知道operator<<有一些右值过载吗?

为什么会这样?

编译器规格

上述结果是通过 AppleClang 11.0.0.11000033 获得的。改用gcc-7.4时,结果始终是std::ostream&,如预期的那样。

完整源代码

#include <iostream>
#include <type_traits>

/* ************************************
 * Sans reference
 * ************************************ */

template<typename T>
struct stream
{
  using type = decltype(
      std::declval<std::ostream>() << std::declval<T>()
    );
};

template<typename T>
using stream_t = typename stream<T>::type;

/* ************************************
 * With reference
 * ************************************ */

template<typename T>
struct stream_ref
{
  using type = decltype(
      std::declval<std::ostream&>() << std::declval<T>()
    );
};

template<typename T>
using stream_ref_t = typename stream_ref<T>::type;

/* ************************************
 * Dummy struct
 * ************************************ */

struct Dummy 
{
  friend std::ostream& operator<<(std::ostream&, const Dummy&);
};

/* ************************************
 * Static asserts
 * ************************************ */

static_assert( std::is_same_v<stream_t<int>,   std::ostream&> );
static_assert( std::is_same_v<stream_t<float>, std::ostream&> );

static_assert( std::is_same_v<stream_t<std::string>, std::ostream&&> );
static_assert( std::is_same_v<stream_t<const char*>, std::ostream&&> );
static_assert( std::is_same_v<stream_t<int*>,        std::ostream&&> );
static_assert( std::is_same_v<stream_t<Dummy>,       std::ostream&&> );

static_assert( std::is_same_v<stream_ref_t<std::string>, std::ostream&> );
static_assert( std::is_same_v<stream_ref_t<const char*>, std::ostream&> );
static_assert( std::is_same_v<stream_ref_t<int*>,        std::ostream&> );
static_assert( std::is_same_v<stream_ref_t<Dummy>,       std::ostream&> );

int main(int argc, char** argv)
{
  return 0;
}

0 个答案:

没有答案