[英]What is the best way to disable implicit conversion from pointer types to bool when constructing an std::variant?
[英]What is the best way to keep a pointer to different types when only one of them is needed at a time?
我处于这样一种情况,我需要一个指向未知类型 object 的指针作为另一个 class 的成员。但是有效 object 类型的列表在编译时是已知的。
说我有:
// A class templated on T
template<class T> class obj;
// Now assume there are some objects of types obj<...> somewhere else
obj<int> obj1;
obj<double> obj2;
// Now, manager needs to create a pointer for these objects
// in a specific manner at construction-time
// Say, we have to choose a canonical object (and set the other as secondary)
// manager shouldn't be templated on T because It needs
// to have multiple members of type obj<...>
template<class R>
class manager
{
shared_ptr<...> canObjPtr;
shared_ptr<...> secObjPtr;
public:
// once set, canonical obj is not expected to change
explicit manager(string canonicalObj);
}
我怎样才能做到这一点?
一些实际上行不通的初步想法:
我能想到的最有前途的方法是将 T1 和 T2 模板 arguments 添加到 manager 并像这样构造: manager<R, obj<int>, obj<double>>()
。 我觉得我应该在管理器构建之前用 static function 获取“canonicalObj”字符串,然后决定创建哪个管理器manager<R, obj<int>, obj<double>>
或manager<R, obj<double>, obj<int>>
。
如何直接在obj1 and obj2
对象上“模板化”管理器。 看起来可行吗? 请注意,我很乐意向管理器添加模板参数,因为它涉及一些不喜欢使用多参数模板的运行时选择机制。
而不是 2 个成员指针,而是创建 4 个(见下文,但这很糟糕,并且在实现中肯定会让我发疯:在使用它们中的任何一个之前,需要始终检查一个指针是否为 null)
template<class R> manager
{
sharedPtr<obj<int>> canObjPtrI;
sharedPtr<obj<float>> canObjPtrF;
// same for secObjPtr above
public:
explicit manager(string canonicalObj);
}
std::any and std::variant
(以及它们的 boost 等效项)是不可能的,因为我想继续使用 c++11 并且不能按策略使用 boost。 如果我要打破其中一条规则,我会考虑升级到 c++17。
我不认为使用shared_ptr<void>
可以带来任何好处,因为无论如何我都必须将指针转换为正确的类型并且不能使用 void 指针的 object 的接口。
union
也是如此。 与 3 相比,它几乎没有任何改进。
另外,如果您认为这是一个潜在的设计问题,请不要犹豫。 我邀请您指出您注意到的任何缺陷/改进。
[编辑]这段代码试图做的是......
基本上,我需要从预先构建的obj<int> and obj<double>
对象列表中选择规范和次要对象,就像我上面解释的那样:
基于用户输入,class 应该决定一个规范的 object 并根据这个决定执行计算。 我已经可以通过名称(字符串)获取对这些对象的引用。 唯一的问题是它们的类型不同,让它们从基类 class 继承会限制我仅使用该基类的接口(这是正确的吗?)。
// A base template for objects defines common
// and possibly different interface.
template<class T> class objBase
{
protected:
field<T> f_;
public:
// Public data type
using fieldType = field<T>;
// New selects from "Registered childs of objBase"
// at runtime
static shared_ptr<objBase>::New() const;
// Pure virtual to update the obj
virtual void update() = 0;
// Const-Access to field
const field<T>& getField() const;
};
// Created objects are also registered automatically to a database
// i.e. I can get (const-)refs to them by querying the database
shared_ptr<objBase<int>> obj1 = objBase<int>::New();
shared_ptr<objBase<int>> obj2 = objBase<int>::New();
shared_ptr<objBase<float>> obj3 = objBase<float>::New();
// In manager, something like this needs to happen
template<class R>
class manager
{
private:
// Read 2 target obj names from user input
pair<string,string> objNames;
// Possible types for requested objs:
// obj_a, obj_b : both objBase<int> or both objBase<float>
// or they can have different types
// But we essentially need only:
pointer<...> canonicalObj;
pointer<...> secondaryObj;
// These should be used like this
void useObjField() const
{
// Not using auto for clarity
const decltype(*canonicalObj)::FieldType& objField
= canonicalObj->getField();
for(int i=0; i < objField.size(); ++i)
{
// Loop through elements and use them for some calculations
// Related to other fields in manager
}
}
};
std::any
和std::variant
(以及它们的 boost 等效项)是不可能的,因为我想继续使用 c++11 并且不能按策略使用 boost。
仍然不是问题:您可以使用mpark::variant
- 它与 C++11 兼容。 还有其他类似的变体 class 实现。 如果你更喜欢 go 和any
-like class(不太推荐),试试 linb linb::any
- 同样的想法; C++11 兼容。
IIANM,这些都是只有头文件的库(忽略测试/示例程序),所以你甚至不需要任何复杂的安装; 你可以只获取 header 的最新版本,或者超级组织,使用 CMake 正确构建和安装它们,然后使用 CMake find_package()
命令找到它们。
最后,“合格联合”将是使用变体的粗略替代方法。 变体本质上是一个联合和一个变量,它告诉您联合中的哪些类型是活动类型。 为了使用的简单性和安全性,我不推荐这样做——但它可能意味着更少的代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.