expected-lite icon indicating copy to clipboard operation
expected-lite copied to clipboard

Non-movable non-copyable expected type fails to compile

Open polasek opened this issue 1 year ago • 5 comments

Based on cppreference, I couldn't see anything that prohibits neither T nor E from being required to be movable or copyable. On gcc 13.1 which implements std::expected, storing a type without copy and move works just fine, but nonstd::expected fails - weirdly when calling .has_value().

The error from nonstd::expected on the same code as the godbolt link above modulo including nonstd/expected.hpp and using namespace nonstd instead of std:

In file included from foo.cc:1:
./nonstd/expected.hpp:1791:26: error: no member named 'has_value' in 'nonstd::expected_lite::detail::storage_t<NonMovableNonCopyable, NonMovableNonCopyable, false, false>'
        return contained.has_value();
               ~~~~~~~~~ ^
foo.cc:17:19: note: in instantiation of member function 'nonstd::expected_lite::expected<NonMovableNonCopyable, NonMovableNonCopyable>::has_value' requested here
  assert(expected.has_value());
                  ^
In file included from foo.cc:1:
./nonstd/expected.hpp:1383:19: error: no member named 'construct_value' in 'nonstd::expected_lite::detail::storage_t<NonMovableNonCopyable, NonMovableNonCopyable, false, false>'
        contained.construct_value( value_type() );
        ~~~~~~~~~ ^
foo.cc:14:66: note: in instantiation of function template specialization 'nonstd::expected_lite::expected<NonMovableNonCopyable, NonMovableNonCopyable>::expected<true, 0>' requested here
  nonstd::expected<NonMovableNonCopyable, NonMovableNonCopyable> expected;
                                                                 ^
In file included from foo.cc:1:
./nonstd/expected.hpp:692:11: error: type 'storage_t_impl<NonMovableNonCopyable, NonMovableNonCopyable>' is not a direct or virtual base of 'nonstd::expected_lite::detail::storage_t<NonMovableNonCopyable, NonMovableNonCopyable, false, false>'
        : storage_t_impl<T, E>( has_value )
          ^~~~~~~~~~~~~~~~~~~~
./nonstd/expected.hpp:1381:7: note: in instantiation of member function 'nonstd::expected_lite::detail::storage_t<NonMovableNonCopyable, NonMovableNonCopyable, false, false>::storage_t' requested here
    : contained( true )
      ^
foo.cc:14:66: note: in instantiation of function template specialization 'nonstd::expected_lite::expected<NonMovableNonCopyable, NonMovableNonCopyable>::expected<true, 0>' requested here
  nonstd::expected<NonMovableNonCopyable, NonMovableNonCopyable> expected;
                                                                 ^
In file included from foo.cc:1:
./nonstd/expected.hpp:1608:7: error: no matching constructor for initialization of 'detail::storage_t<NonMovableNonCopyable, NonMovableNonCopyable, std::is_copy_constructible<NonMovableNonCopyable>::value && std::is_copy_constructible<NonMovableNonCopyable>::value, std::is_move_constructible<NonMovableNonCopyable>::value && std::is_move_constructible<NonMovableNonCopyable>::value>'
    : contained( false )
      ^          ~~~~~
foo.cc:15:66: note: in instantiation of function template specialization 'nonstd::expected_lite::expected<NonMovableNonCopyable, NonMovableNonCopyable>::expected<0>' requested here
  nonstd::expected<NonMovableNonCopyable, NonMovableNonCopyable> unexpected(nonstd::unexpect_t{});
                                                                 ^
./nonstd/expected.hpp:695:5: note: candidate constructor not viable: no known conversion from 'bool' to 'const nonstd::expected_lite::detail::storage_t<NonMovableNonCopyable, NonMovableNonCopyable, false, false>' for 1st argument
    storage_t( storage_t const & other ) = delete;
    ^
./nonstd/expected.hpp:696:5: note: candidate constructor not viable: no known conversion from 'bool' to 'nonstd::expected_lite::detail::storage_t<NonMovableNonCopyable, NonMovableNonCopyable, false, false>' for 1st argument
    storage_t( storage_t &&      other ) = delete;
    ^
./nonstd/expected.hpp:688:5: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
    storage_t() = default;
    ^
./nonstd/expected.hpp:1610:19: error: no member named 'emplace_error' in 'nonstd::expected_lite::detail::storage_t<NonMovableNonCopyable, NonMovableNonCopyable, false, false>'
        contained.emplace_error( std::forward<Args>( args )... );
        ~~~~~~~~~ ^
5 errors generated.

This is with

Apple clang version 14.0.3 (clang-1403.0.22.14.1)
Target: arm64-apple-darwin22.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

However, I have seen the same error on gcc 11.3 on Linux with -std=c++20.

Am I missing something that says I can't do this and is gcc just being overly permissive, or is this an issue with the library?

polasek avatar Jun 22 '23 09:06 polasek

@polasek Thanks for bringing this up and for the PR.

There have been issues with non-movable, non-copyable elements before, such as issue #32.

Hope to look at your PR today/tomorrow.

martinmoene avatar Jun 22 '23 14:06 martinmoene

I can’t see a comment I got a notification about via email, and I am assuming you found what you were missing but just in case this is Github glitching, the Godbolt is C++23 since that’s where std::expected is implemented and I wanted to show that gcc’s official version does seem to work fine in the case I described.

polasek avatar Jun 22 '23 15:06 polasek

Yeah, forgot std:: expected wasn't available until C++23.

martinmoene avatar Jun 22 '23 16:06 martinmoene

@polasek Above commits should solve this issue.

Separation of concerns may be improved upon, something I hope to look into later.

martinmoene avatar Jun 23 '23 11:06 martinmoene

Great @martinmoene , thanks for the quick turnaround! Your fix does seem to address the compilation issue and I haven't seen any other problems.

polasek avatar Jun 23 '23 19:06 polasek