代码之家  ›  专栏  ›  技术社区  ›  Adam Barnes

我如何在`std::expected<T,E>上使用`.value()`,其中`T`是只移动的类型?

  •  1
  • Adam Barnes  · 技术社区  · 7 月前

    以下代码:

    #include <chrono>
    #include <expected>
    #include <stdexcept>
    #include <string>
    #include <thread>
    #include <utility>
    
    using namespace std::literals;
    
    class Resource {
    
      Resource() { /* some setup, might raise */ }
    
      public:
      static std::expected<Resource, std::string> tryCreate() noexcept {
        try {
          return Resource();
        } catch (const std::runtime_error& exc) {
          return std::unexpected(exc.what());
        }
      }
      static const Resource create() noexcept {
        while (true) {
            const auto resource{Resource::tryCreate()};
            if (resource.has_value()) return resource.value();  // <-- this is no good.
            else std::this_thread::sleep_for(1s);
        }
      }
      Resource(const Resource&) = delete;
      Resource(Resource&& other) noexcept {}
      Resource& operator=(const Resource&) = delete;
      Resource& operator=(Resource&& other) noexcept { return *this; }
      ~Resource() { /* some cleanup */ }
    
      void use() const noexcept {}
    };
    
    int main() noexcept {
        const auto resource{Resource::create()};
        resource.use();
    }
    

    …拒绝编译,出现错误:

    <source>:25:42: error: call to deleted constructor of 'const Resource'
       25 |         if (resource.has_value()) return resource.value();
          |                                          ^~~~~~~~~~~~~~~~
    <source>:29:3: note: 'Resource' has been explicitly marked deleted here
       29 |   Resource(const Resource&) = delete;
          |   ^
    1 error generated.
    Compiler returned: 1
    

    我没有看到任何解释 cppreference 只允许移动的类型是不允许的,而且我在搜索互联网时无法立即找到其他有类似问题的人(尽管我对此还不熟悉,所以我的C++google fu可能不够)。我认为这可能与“复制省略”有关,但我真的很困惑。

    是否不能使用仅限移动的类型 std::expected ?如果是,我如何修改我的示例代码使其正常工作(不定义复制构造函数)?

    godbolt -在Clang上使用-std=c++23失败,但我在GCC 14.2.1上遇到了类似的情况,同样是在-std=c++23上。

    1 回复  |  直到 7 月前
        1
  •  2
  •   Sebastian Redl    7 月前

    存在右值过载 value() 它返回一个右值引用。所以你可以写 return std::move(resource).value(); 但为此,当地 resource 变量不得为 const .