Why is std :: is_assignable counter-intuive?

std::is_assignable<int, int>::value == false in the corresponding implementation (for example, clang / lib ++, gcc / libstd ++, but not VS2012).

Intuitively, this means an expression such as int x = 3; is invalid. But the is_assignable specification states that both sides of the assignment are converted to std::add_rvalue_reference<T>::type , so std::is_assignable<int, int>::value must evaluate to false (because int + && β†’ int&& , which is the inapplicable value of r).

Why is the design of std::is_assignable designed this way, or do I not understand something about what is_assignable<int, int>::value really means?

Related discussions:

  • Inconsistent results is_assignable <gt; .
  • What is the difference between is_convertible is_assignable .
+12
c ++ c ++ 11 typetraits
source share
3 answers

In these features, T is not a reference type of lvalue, T implies rvalue.

With many custom T types, it is wise to assign rvalue types. And this is even very useful in some contexts:

 std::vector<bool> v(5); v[0] = true; 

In the above expression, v[0] is the value of r to which the value is assigned. And if vector<bool> is a bad example, then the following new C ++ 11 code does the same:

 #include <tuple> std::tuple<int, int> do_something(); int main() { int i, j; std::tie(i, j) = do_something(); } 

Above, the result of do_something() assigned to rvalue std::tuple . Assigning r values ​​is useful and even common, although not done in the vast majority of assignment applications.

So, std::is_assignable allows you to distinguish between the ability to assign the value of r and lvalue. If you need to know the difference, std::is_assignable can do your job.

If you are dealing with a more common case, for example, just trying to figure out if type T is an assignable copy or not, use is_copy_assignable<T> . This trait is literally defined in terms of is_assignable and forces lhs to lvalue:

 is_copy_assignable<T> == is_assignable<T&, const T&> 

So std::is_copy_assignable<int>::value will be true as expected.

Use is_copy_assignable as your first choice, or is_move_assignable if you need it. Only when these traits do not work for you (perhaps because you need to look at the heterogeneous destination) should you return to using is_assignable directly. And then you need to solve the question of whether you want to allow rvalues ​​to lhs in order to take into account cases that may include vector<bool>::reference or tuple links. You will need to explicitly indicate whether you want to resolve such cases in your is_assignable request.

For example:

 #include <type_traits> #include <vector> int main() { static_assert(std::is_assignable<std::vector<bool>::reference&, bool>(), "Should be able to assign a bool to an lvalue vector<bool>::reference"); static_assert(std::is_assignable<std::vector<bool>::reference, bool>(), "Should be able to assign a bool to an rvalue vector<bool>::reference"); static_assert(std::is_assignable<bool&, std::vector<bool>::reference>(), "Should be able to assign a vector<bool>::reference to an lvalue bool"); static_assert(!std::is_assignable<bool, std::vector<bool>::reference>(), "Should not be able to assign a vector<bool>::reference to an rvalue bool"); } 
+21
source share

std::is_assignable<int, int>::value == false means that "an int literal cannot be assigned to an int literal" (among other things).

Your int x = 3 expression is std::is_assignable<int&, int>::value .

For more information: http://en.cppreference.com/w/cpp/types/is_assignable

+7
source share

The pragmatic answer is that you can get what you usually want by changing the left argument.

The request std::is_assignable_t<T&,U> will tell you if you can intelligently write code such as:

 T t; U u; t = u; 

I say this pragmatically because if they wrote std::is_assignable<> to use the lvalue inline link on the left, it would be harder to reuse this alternative to get its current functionality. It’s easier if a user adds an lvalue link to an arbitrary type outside (it won’t be deleted) than requiring an rvalue link outside for another request (which can be easily removed).

So, this version of std::is_assignable<> will meet your typical lvalue receive from rvalue assignment test, but also more rare requests.

The penalty for this flexibility is the inconsistency that you described.

0
source share

All Articles