Invalid possible implementation of is_move_constructible (same used by MSVC 2015)

62 views
Skip to first unread message

Alexey Mamontov

unread,
Sep 25, 2016, 5:36:28 AM9/25/16
to ISO C++ Standard - Future Proposals


template<class T>
struct is_move_constructible :
      std::is_constructible<T, typename std::add_rvalue_reference<T>::type> {};

The problem is that in this case it will be true for any class which is copy constructible, which is not the desired result. For example I would like to implement something like this:

 template<typename T, bool move_constructible = std::is_move_constructible<T>::value>
 
struct choose_best_input_modifier;
 
template<typename T>
 
struct choose_best_input_modifier<T, true>
 
{
   
typedef T&& type;
 
};

 
template<typename T>
 
struct choose_best_input_modifier<T, false>
 
{
   
typedef const T& type;
 
};

#define MOVED(...) choose_best_input_modifier<__VA_ARGS__>::type
#define MOVED_T(...) typename choose_best_input_modifier<__VA_ARGS__>::type // the typename issue, just another issue, but ok...


template<typename T>
void func(MOVED_T(T) x) // T&& if available or const T& otherwise
{
  cout
<< typeid(x).name();
}
void func2(MOVED(string) x) // string&&
{
  cout
<< typeid(x).name();
}
void funcNM(MOVED(NM) nm) // const NM&
{
  cout
<< typeid(nm).name();
}

But I can't...




Nicol Bolas

unread,
Sep 25, 2016, 5:13:27 PM9/25/16
to ISO C++ Standard - Future Proposals
On Sunday, September 25, 2016 at 5:36:28 AM UTC-4, Alexey Mamontov wrote:


template<class T>
struct is_move_constructible :
      std::is_constructible<T, typename std::add_rvalue_reference<T>::type> {};

The problem is that in this case it will be true for any class which is copy constructible, which is not the desired result.

The question answered by `is_move_constructible` is whether `A(std::move(a_val))` will compile. Since an xvalue can bind to a const lvalue reference, that expression may provoke the calling of a copy constructor. But that's fine for that purpose; it's no different from having `is_constructible` take into account implicit conversions and such.

The question you seem to want answered is "is there a constructor with this exact signature?" The standard library doesn't have a traits class as of yet. Are you suggesting that we add one?

For example I would like to implement something like this:

This is something of an aside, but what you seem to want looks like a really bad idea. You should not select whether to take a `const&` or a `&&` based on whether the type in question has a move constructor. You pick it based on what the function is actually doing with it.

If your function doesn't need modifiable access to an object, it should take a `const&`. If you intend to copy/move from the parameter, then you take it by value or by `&&`.

David Krauss

unread,
Sep 26, 2016, 12:48:52 AM9/26/16
to std-pr...@isocpp.org

On 2016–09–25, at 5:36 PM, Alexey Mamontov <cara...@gmail.com> wrote:

The problem is that in this case it will be true for any class which is copy constructible, which is not the desired result.

If you want to check whether moving is more efficient than copying, is_nothrow_move_constructible might help. This depends on noexcept correctness of user-defined move constructors.

Nicol Bolas

unread,
Sep 26, 2016, 1:47:52 AM9/26/16
to ISO C++ Standard - Future Proposals

That would lead to dysfunctional code. Imagine a class like `std::list`, but is move-only. Such a class would not be nothrow move constructible, and it wouldn't be copy constructible. So... what do you pick?

At the end of the day, there's no way to guaranteeably know if moving is more efficient than copying. However, moving will in virtually every case be no less efficient than copying (even with `std::list`).

David Krauss

unread,
Sep 26, 2016, 3:52:08 AM9/26/16
to ISO C++ Standard - Future Proposals
On 2016–09–26, at 1:47 PM, Nicol Bolas <jmck...@gmail.com> wrote:

That would lead to dysfunctional code. Imagine a class like `std::list`, but is move-only. Such a class would not be nothrow move constructible, and it wouldn't be copy constructible. So... what do you pick?

“Might help” is weaker than “will immediately solve this problem.”

By itself, to me, choose_best_input_modifier has some code smell. What’s its ultimate goal? Possibly to combat template bloat by shifting degenerate move constructor calls to copy constructors. In that case, “throwing move construction ≈ copy construction” could be a reasonable approximation, but likely not a slam dunk. (Even going that route, SFINAE might be a better way of coding it.)

At the end of the day, there's no way to guaranteeably know if moving is more efficient than copying. However, moving will in virtually every case be no less efficient than copying (even with `std::list`).

Right. Usual best practice is to move when it’s safe, forward when unsure, and let dispatching and inlining take care of the rest.

Reply all
Reply to author
Forward
0 new messages