0

This is my attempt at an implementation for is_copy_assignable:

template<typename, typename = void>
struct IsCopyAssignable : std::false_type
{};

template<typename T>
struct IsCopyAssignable<T, decltype(std::add_lvalue_reference<T>::type = std::add_lvalue_reference<const T>::type, void())> : std::true_type
{};

It was a failure.

Here's the test cases:

int main()
{
    struct Structure {};
    std::cout << "IsCopyAssignable=\n";
    std::cout << IsCopyAssignable<int>::value << '\n'; // should be true
    std::cout << IsCopyAssignable<int&>::value << '\n'; // should be true
    std::cout << IsCopyAssignable<const int&>::value << '\n'; // should be false
    std::cout << IsCopyAssignable<const double&>::value << '\n'; // should be false
    std::cout << IsCopyAssignable<class Structure>::value << '\n'; // should be true
    std::cout << '\n';
}

They all print false.

(I realized then that declval in combination with the handy void_t - and decltype of course - can be used for things like these instead.) But I still do not understand exactly why this one doesn't work. I think we want to test whether const T& can be assigned to T& (as the copy assignment operator does). Well, why then?

KeyC0de
  • 4,728
  • 8
  • 44
  • 68
  • `int& = const int&` wouldn't make any sense. Probably you want to put `std::declval::type>()` etc. in there. – Daniel Schepler Sep 20 '18 at 23:41
  • @DanielSchepler That's an answer. Basically, what you noticed is that the specialization always SFINAEs away because it doesn't make sense. – Justin Sep 20 '18 at 23:50
  • Technically, you might be able to make `IsCopyAssignable::value` be true if you made specializations like `template<> struct std::add_lvalue_reference { static bool type; };` and similarly for `std::add_lvalue_reference` - though naturally the standard also makes this undefined behavior... – Daniel Schepler Sep 21 '18 at 00:09

1 Answers1

1

Your decltype(std::add_lvalue_reference<T>::type = std::add_lvalue_reference<const T>::type, void()) is ill formed for every T as std::add_lvalue_reference<T>::type is actually not a value, but a type.

std::declval might help:

You want to check instead expression std::declval<T&>() = std::declval<const T&>() is valid.

So

template<typename T>
struct IsCopyAssignable<T,
                       decltype(std::declval<T&>() = std::declval<const T&>(), void())>
       : std::true_type
{};
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Yes. But, shouldn't we deal with types and not values inside the expression created in the "unevaluated context" of a `decltype`? – KeyC0de Sep 21 '18 at 00:14
  • `decltype` return the type of given expression, and value are used in expression, not type. `i = 42` versus `int& = int`. – Jarod42 Sep 21 '18 at 00:18