Home > OS >  using declval with reference types
using declval with reference types

Time:05-15

I would like to understand how the assignment of int & to double below in conjunction with declval works? Is T deduced to something other than 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?

}

CodePudding user response:

Is T deduced to something other than int & ?

T will still be deduced as int&, so std::declval<T>() = std::declval<U>() will be roughly equivalent to

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

f() = g(); // assignment

Note that f() = g() is still well-formed because f() returns a reference to an already created int that can be assigned to a double. But if you do int& f() { return 23.4; }, then you will get a compile error because non-const lvalue references cannot be initialized by a rvalue. Instead, you can create a helper function which take T as its parameter type

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 {}; 

This will make static_assert(initialize<int &, double>::value) fail because int& cannot be rvalue-initialized.

  • Related