确保在编译期间仅同时使用来自同一工厂的对象

  • 本文关键字:工厂 对象 编译 确保 c++
  • 更新时间 :
  • 英文 :


我想确保由Thing::Factory的不同实例创建的Thing实例不能combined。

以下代码在运行时就是这样做的:

#include <cassert>
struct Thing {
struct Factory {
Thing make() {return Thing(this);}
};
static void combine(Thing t1, Thing t2) {
assert(t1.factory == t2.factory);
}
private:
Thing(Factory* factory_) : factory(factory_) {}
Factory* factory;
};
int main() {
Thing::Factory f1;
Thing t11 = f1.make();
Thing t12 = f1.make();
Thing::combine(t11, t12);
Thing::Factory f2;
Thing t21 = f2.make();
Thing t22 = f2.make();
Thing::combine(t21, t22);
Thing::combine(t11, t21); // Assertion failure
}

问题:在编译过程中有没有办法做到这一点?

我试过Thing模板:

template<typename Tag>
struct Thing {
// Same code as before
};

并将客户端代码修改为:

struct Tag1;
struct Tag2;
int main() {
Thing<Tag1>::Factory f1;
Thing<Tag1> t11 = f1.make();
Thing<Tag1> t12 = f1.make();
Thing<Tag1>::combine(t11, t12);
Thing<Tag2>::Factory f2;
Thing<Tag2> t21 = f2.make();
Thing<Tag2> t22 = f2.make();
Thing<Tag2>::combine(t21, t22);
}

那就没有办法combinet11t21了。 好的。

但仍然存在问题:

  • 没有什么能阻止创建另一个Thing<Tag1>::FactorycombinemakeThingt11
  • 客户端必须手动声明标记类型

有没有一种模式也可以解决这些问题?

在回答之前,听起来您遇到了 X-Y 问题; 和 - 我怀疑你选择了正确的 Y。 考虑完全删除这些工厂,或者 - 仅将一个工厂用于具有公共基类的许多类。


为了在编译时实现这一点,工厂需要生成不同类型的值,或者combine()必须能够在编译时运行。但是combine()constexpr 对你没有帮助,因为工厂只在运行时生产输出......所以是的,类型差异化是您唯一的选择。我想某种标记很好 - 但是如果您可以先验地提供这些标签,为什么不从一开始就拥有不同的类型呢?就像你自己说的,目前还不清楚这些标签应该来自哪里。

无论如何,要禁止创建两个相同类型的工厂,您可以使用单例模式。无论如何,工厂在运行时工作,不妨让它在运行时创建。

  • 没有什么禁止创建另一个 Thing::Factory 并将它制造的东西与 t11 结合起来

您可以有一个通用工厂基础,该基础在工厂构造函数中保留std::type_info初始化的标记实例的静态std::set

如果该条目已在该std::set中,则可以引发运行时异常

  • 客户端必须手动声明标记类型

您还可以为工厂实例生成 ID,而不是使用模板参数。

最新更新