c++ - 我如何围绕概念和不完整类型的限制进行设计?

标签 c++ c++20 c++-concepts incomplete-type

我有这样的东西:

template <typename T>
requires ::std::movable<T> || ::std::copyable<T> || ::std::is_void_v<T>
class ValueWrapper
{
   // various functions to do stuff with value
};

class Value {
 public:
    Value(Value const &) = delete;
    Value &operator =(Value const &) = delete;
    Value(Value &&other) noexcept : x_{other.x_} { other.x_ = -1; }
    Value &operator =(Value &&other) {
        Value tmp{::std::move(other)};
        x_ = tmp.x_;
        tmp.x_ = -1;
        return *this;
    }

ValueWrapper<Value> do_something() const;  // Generates error related to incomplete type. :-(

 private:
    int x_;
};

它当然不起作用,因为当编译器看到 do_something 声明时,Value 是一个不完整的类型,并且不可能测试可移动或可复制的不完全类型,并且它不是无效的。

我应该如何围绕这个进行设计?

我可以更改 ValueWrapper,以便各个成员函数需要一些东西,而不是让类需要一些模板参数。但是,这似乎很迟钝,因为该类的目的是包装可移动或可复制的东西。我可以将 do_somethingValue 类中移出,并使其成为一个自由函数。但这似乎过于严格,对于任何 Value 类的方法来说可能都不是明智的做法。

还有没有这些缺点的其他设计选择吗?

在我当前关注的特定非抽象情况下,ValueWrapper 恰好类似于 Boost expected,因此被用来表示错误或值(value)返回。

编辑:到目前为止,我最喜欢的答案涉及使用auto,并且要求函数定义内联显示才能工作。如果您希望函数定义不内联,您可以做这些练习。不过,确实很奇怪。

#include <concepts>
#include <utility>


template <typename T>
requires ::std::movable<T> || ::std::copyable<T> || ::std::is_void_v<T>
class ValueWrapper
{
   // various functions to do stuff with value
};

namespace priv_ {
    // We can forward declare a class without its member functions.
    // But we can't forward declare a function without being able to
    // fully name all of its types.
    class Silly;
}

class Value {
 public:
    Value() : x_{-1} { }
    Value(Value const &) = delete;
    Value &operator =(Value const &) = delete;
    Value(Value &&other) noexcept : x_{other.x_} { other.x_ = -1; }
    Value &operator =(Value &&other) {
        Value tmp{::std::move(other)};
        x_ = tmp.x_;
        tmp.x_ = -1;
        return *this;
    }

    // inline here is basically documenting that we intend to give an
    // inline definition later. We might want to say what the actual
    // return type is too.
    auto inline do_something() const;

 private:
    int x_;

    // And we can friend a forward declared class so all of its member
    // functions are basically member functions of this class (and
    // hence have unrestricted access to all member functions and
    // variables).
    friend class priv_::Silly;
};

namespace priv_ {
    class Silly {
     public:
        // And finally, now that the Value type is 'complete', we can
        // use it as a parameter to the `ValueWrapper` template type.
        static ValueWrapper<Value> p_do_something(Value const &v);
    };
}

auto inline Value::do_something() const
{
    // And now that the declaration for `p_do_something` has been
    // seen, we can call it.
    return priv_::Silly::p_do_something(*this);
}

ValueWrapper<Value> foo()
{
    Value v;
    return v.do_something();
}

最佳答案

该类型在成员函数定义中是完整的,因此我们可以使用推导的返回类型:

auto do_something() const {
    return ValueWrapper<Value>();
}

关于c++ - 我如何围绕概念和不完整类型的限制进行设计?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67234340/

相关文章:

std::transform_reduce 的 C++17 替代实现

c++ - 是否有比 swap-and-pop 更快的方法来从 std::vector 中删除?

c++ - std::ranges::elements_view 用于自定义元组数据

c++ - 标准库中自赋值不安全的 move 赋值运算符的基本原理是什么?

c++ - 我如何调用 dataChanged

c++ - 棒球击球率计划

c++ - 假设的、以前的 C++0x 概念问题

c++ - 在 Visual Studio 中加载文本文件资源比它应该加载的更多

c++ - 在 MSVC19 中的 lambda 中捕获可变参数包的问题

c++ - boost 概念检查 operator() 重载