Tor*_*örn 10 c++ api-design c++14 c++17
我正在设计一个从头开始的库,并希望尽可能好地获得公共API .我希望编译器因误用而对我大喊大叫.因此,我对自己施加了以下规则:
整个库中的true(即深度和完整)const正确性
声明不会发生变化的所有事物(局部变量,成员变量,成员函数)const.该constness应该传播到所有嵌套的成员和类型.
明确和富有表现力的所有权
根据C++核心指南,我将其定义为(iff在数学意义上的if和only if):
unique_ptr<T>或T&& iff函数正在消耗它(即取得所有权)shared_ptr<const T>或T const& iff函数只读它shared_ptr<T>或者T& 如果函数正在修改它而不取得所有权unique_ptr<T>或T iff函数将所有权转移给调用者shared_ptr<const T>或T const& iff调用者只应读取它(虽然调用者可以构造它的副本 - 给定T是可复制的)shared_ptr<T>,T&或T*(因为它会允许无法控制的副作用,我试图通过设计避免)隐藏的实施细节
现在,我将使用抽象接口与工厂将实现作为一个返回unique_ptr<Interface>.虽然,我愿意接受解决我下面描述的问题的替代模式.
我不关心虚拟表查找,并希望通过各种方式避免动态转换(我将它们视为代码气味).
现在,给出了两个班A和B,其中B拥有可变数量的A秒.我们也有 - B实现BImpl(A这里可能没有使用的实现):
class A
{};
class B {
public:
virtual ~B() = default;
virtual void addA(std::unique_ptr<A> aObj) = 0;
virtual ??? aObjs() const = 0;
};
class BImpl : public B {
public:
virtual ~BImpl() = default;
void addA(std::unique_ptr<A> aObj) override;
??? aObjs() const override;
private:
std::vector<unique_ptr<A>> aObjs_;
};
Run Code Online (Sandbox Code Playgroud)
我坚持使用Bs getter 的返回值到As:的向量aObjs().
它应该提供As 列表作为只读值而不转移所有权(规则2.5.上面带有const正确性)并且仍然为调用者提供对所有As的轻松访问,例如用于基于范围的for或标准算法,例如std::find.
我想出了以下选项???:
std::vector<std::shared_ptr<const A>> const&
每次调用时我都必须构造一个新的向量aObjs()(我可以将其缓存BImpl).这感觉不仅低效且不必要地复杂,而且似乎也非常不理想.
替换aObjs()为一对函数(aObjsBegin()和aObjsEnd())转发常量迭代器BImpl::aObjs_.
等待.我需要做unique_ptr<A>::const_iterator一个unique_ptr<const A>::const_iterator让我心爱的const正确.再次讨厌的演员或中间对象.并且用户无法在基于范围的情况下轻松使用它for.
我错过了什么明显的解决方案?
编辑:
B应该总是能够修改A其持有S,从而宣告aObjs_为vector<std::unique_ptr<const A>>不是一种选择.
让我们B遵循迭代器概念迭代As,既不是一个选项,因为B它将保存一个Cs 列表和一个特定的D(或没有).
使用range-v3,你可以这样做
template <typename T>
using const_view_t = decltype(std::declval<const std::vector<std::unique_ptr<T>>&>()
| ranges::view::transform(&std::unique_ptr<T>::get)
| ranges::view::indirect);
class B
{
public:
virtual ~B() = default;
virtual void addA(std::unique_ptr<A> a) = 0;
virtual const_view_t<A> getAs() const = 0;
};
class D : public B
{
public:
void addA(std::unique_ptr<A> a) override { v.emplace_back(std::move(a)); }
const_view_t<A> getAs() const override {
return v | ranges::view::transform(&std::unique_ptr<A>::get)
| ranges::view::indirect;
}
private:
std::vector<std::unique_ptr<A>> v;
};
Run Code Online (Sandbox Code Playgroud)
进而
for (const A& a : d.getAs()) {
std::cout << a.n << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
337 次 |
| 最近记录: |