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.