将 declval 与引用类型一起使用

using declval with reference types

我想了解下面将 int & 赋值给 double 以及 declval 是如何工作的? T 是否推导出 int & 以外的东西?

#include <iostream>
#include <type_traits>
#include <utility>

template <typename T, typename U, typename = void>
struct assignment : std::false_type{};

template <typename T, typename U>
struct assignment<T, U, std::void_t<decltype(std::declval<T>() = std::declval<U>())>> : std::true_type {}; 
 

int main() {
    // int &x = 23.4; // does not compile since x is not a const ref
    static_assert(assignment<int &, double>::value);  // why is this OK?

}

Is T deduced to something other than int & ?

T会仍然推导为int&,所以std::declval<T>() = std::declval<U>()会大致等价于

int& f();
double&& g();

f() = g(); // assignment

请注意,f() = g() 仍然是 well-formed,因为 f() returns 是对已创建的 int 的引用,可以 分配double。但是如果你这样做 int& f() { return 23.4; },那么你会得到一个编译错误,因为非 const 左值引用不能被右值 初始化。相反,您可以创建一个将 T 作为其参数类型

的辅助函数
template <typename T, typename U, typename = void>
struct initialize : std::false_type{};

template<typename T>
void accepted(T);

template <typename T, typename U>
struct initialize<T, U, 
  std::void_t<decltype(accepted<T>(std::declval<U>()))>> : std::true_type {}; 

这将使 static_assert(initialize<int &, double>::value) 失败,因为 int& 不能是 rvalue-initialized。