Search code examples
c++template-meta-programmingoverload-resolution

How do I remove a special constructor from overload resolution?


I'm creating an implementation of C++17's std::optional<class T> in C++14. The specification states that the move constructor should be excluded from overload resolution if T is not move-constructible, and made trivial if T is trivially move-constructible. I'm stuck on getting the former.

Here's a code sample of what I have so far:

    template<class T, bool = is_trivially_move_constructible_v<T>>
    class optional_move_construct : public optional_copy_construct<T> {
    public:
      optional_move_construct(optional_move_construct&& rhs) :
        optional_base<T>() {
        if (rhs.m_full) {
          _impl_construct(std::move(rhs.m_value));
        }
      }
    };

optional_copy_construct<T> is part of the inheritance chain I'm using, so I won't worry about it.

There are two ways I can "remove" the move constructor, neither of which works for this scenario.

Option 1: Delete the move constructor. This won't work because deleted functions are included in overload resolution.
Option 2: Use SFINAE to exclude the move constructor from overload resolution. This won't work either, because SFINAE requires a template function to work, and that would be lower-priority than the default move constructor.

How would I go about doing this?


Solution

  • A move constructor has one T&& argument, and possibly additional arguments provided those have default values. That means you can add std::enable_if_t<Condition, int> = 0 as an additional argument to your move constructor.

    The compiler won't create a one-argument optional::optional(T&&) move constructor when you have that two-argument move constructor.