Why is std::is_assignable counter-intuitive?

前端 未结 3 652

std::is_assignable::value == false in a conforming implementation (e.g. clang/libc++, gcc/libstdc++, but not VS2012).

Intuitively, this

相关标签:
3条回答
  • 2021-01-02 01:23

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

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

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

    0 讨论(0)
  • 2021-01-02 01:30

    In these traits, and with T not being an lvalue reference type, T implies an rvalue.

    With many user-defined types T, it is perfectly reasonable to assign to rvalue types. And it is even very useful in some contexts:

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

    In the above expression, v[0] is an rvalue which is getting assigned to. And if vector<bool> is a poor 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() is being assigned to an rvalue std::tuple. Assigning to rvalues is useful, and even common, though not done in the great majority of uses of assignment.

    So std::is_assignable allows for the determining the distinction between being able to assign to an rvalue and to an lvalue. If you need to know the difference, std::is_assignable can do the work for you.

    If you are dealing with a more common case, such as just trying to figure out if a type T is copy assignable or not, then use is_copy_assignable<T>. This trait is literally defined in terms of is_assignable and forces the lhs to an 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 that too. Only when those traits don't work for you (perhaps because you need to look at a heterogeneous assignment), should you revert to using is_assignable directly. And then you need to deal with the question of whether or not you want to allow rvalues on the lhs so as to account for cases that might involve a vector<bool>::reference, or a tuple of references. You will have to explicitly choose whether or not you want to allow such cases in your is_assignable query.

    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");
    }
    
    0 讨论(0)
  • 2021-01-02 01:31

    A pragmatic answer is that you can get what you usually want by modifying your left argument.

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

    T t;
    U u;
    t = u;
    

    I say it's pragmatic because if they had written std::is_assignable<> to use a built-in lvalue reference on the left, it would have been more difficult to reuse this alternative to obtain its current functionality. It's simpler if the user adds an lvalue reference to an arbitrary type on the outside (it won't get erased) than to require an rvalue reference on the outside for a different query (which can easily be erased).

    So, this version of std::is_assignable<> will answer your typical "lvalue receiving from rvalue" assignment test, but also more rare queries too.

    The penalty for this flexibility is the counter-intuitive nature that you described.

    0 讨论(0)
提交回复
热议问题