Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inconsistent results of is_assignable<> [duplicate]

Tags:

c++

Possible Duplicate:
What is the difference between is_convertible is_assignable

I use this test code:

cout<<std::is_assignable<int, int>::value<<endl;
cout<<std::is_assignable<int, char>::value<<endl;
cout<<std::is_assignable<int&, int>::value<<endl;
cout<<std::is_assignable<int&, char>::value<<endl;
cout<<std::is_assignable<int, int&>::value<<endl;
cout<<std::is_assignable<int, char&>::value<<endl;

The result in vs2012 is:

true
true
true
true
true
true

In gcc4.7.2 I get:

false
false
true
true
false
false

Which result is correct according to the standard?

like image 812
chiyer Avatar asked Dec 19 '12 15:12

chiyer


2 Answers

is_assignable<T,U> is true if:

The expression declval<T>() = declval<U>() is well-formed

declval<T> is declared as a function returning a reference to T:

template <class T>
  typename add_rvalue_reference<T>::type declval() noexcept;

where add_rvalue_reference<T>::type is an rvalue reference type (T&&) if T is an object or function type, or T itself if it is a reference type.

This means that is_assignable<T,U> can only be true if T is a non-const lvalue reference type. If it's an object type, then add_rvalue_reference<T>::type is an rvalue reference type; so the expression declval<T>() is an xvalue, which cannot be assigned to.

So, unless I've misread the standard, GCC is correct and VS2012 is wrong. Even if it might seem to make more sense for is_assignable<int,int> to be true, it is not.

like image 119
Mike Seymour Avatar answered Nov 19 '22 02:11

Mike Seymour


is_assignable<T,U>::value is defined as true when declval<T>() = declval<U>() is well-formed and declval<T> is defined as a function returning add_rvalue_reference<T>::type.

We must remember that an assignment is only valid for a modifiable lvalue as the left operand. Also remember the rules of reference collapsing (especially the last two):

T&  &  -> T&
T&& &  -> T&
T&  && -> T&
T&& && -> T&&

So each case:

  1. is_assignable<int, int> and is_assignable<int, char>

    Can we assign the result of a function returning an rvalue reference (an xvalue) to the result of another function returning an rvalue reference (another xvalue). No we can't. This should be false.

  2. std::is_assignable<int&, int> and std::is_assignable<int&, char>

    Can we assign the result of a function returning an rvalue reference (an xvalue) to the result of a function returning an lvalue reference (an lvalue). We sure can. This should be true.

  3. std::is_assignable<int, int&> and std::is_assignable<int, char&>

    Can we assign the result of a function returning an lvalue reference (an lvalue) to the result of a function returning an rvalue reference (an xvalue). No we can't. This should be false.

So I say GCC is right here.

like image 31
Joseph Mansfield Avatar answered Nov 19 '22 03:11

Joseph Mansfield