c++:传达可以使用的允许类的列表
c++: Communicating a list of allowed classes which can be used
我有两组类,比如集合A = {a1, a2, a3}
都派生自Asuper
,B = {b1, b2}
都派生自Bsuper
,只有包含A和B的类可以一起使用(例如a1和b2,或a3和b1;它们有逻辑依赖关系)。如何通过适当的类设计将其传达给用户?
一种方法是让枚举与每个类相关联并将它们呈现在某个地方。例如:
class LogicalGrouping{
enum gr1{A1, A2, A3};
enum gr2{B1, B2};
Asuper *a;
Bsuper *b;
setA(Asuper *a); //user can now manually check the types in gr1 and assign
setB(Bsuper *b);
};
但在我看来,这非常丑陋。必须手动解码枚举的含义并分配它们。我想要一个类似类列表的东西,例如classlist {a1, a2, a3};
有没有更清洁的方法?
创建两个接口 IA 和 IB,让所有 A 实现 IA,所有 B 实现 IB,然后创建继承自 IA 和 IB 的第三个接口 IAB。这将确保您拥有其中之一。
当你的类的用户想要使用你的类时,他需要从IAB继承,这迫使他选择一个A和一个B。
这花了很长时间,但这是我根据@TartanLlama的建议(或多或少)想出的代码:
#include <iostream>
#include <cassert>
#include <type_traits>
#include <typeinfo>
#include <string>
//--- The class hierarchy
struct A{ virtual std::string name() const{ return "A";} };
struct B{ virtual std::string name() const{ return "B";} };
template <int i> struct An : A
{
virtual std::string name() const{ return A::name() + std::to_string(i);}
};
template <int i> struct Bn : B
{
virtual std::string name() const{ return B::name() + std::to_string(i);}
};
template <int i> struct AnBn : An<i>, Bn<i>
{
virtual std::string name() const{ return An<i>::name() + Bn<i>::name(); }
};
template <int i,int j> struct AnBm : An<i>, Bn<j>
{
virtual std::string name() const{ return An<i>::name() + Bn<j>::name(); }
};
//--- End of class hierarchy
//--- The magic that determines whether A/B is base of
template <class T> using A_is_base_of =
std::is_base_of<A,typename std::remove_reference<T>::type>;
template <class T> using B_is_base_of =
std::is_base_of<B,typename std::remove_reference<T>::type>;
template <class T>
struct AB_is_base_of
{
const static bool value = A_is_base_of<T>::value && B_is_base_of<T>::value;
typedef typename std::integral_constant<bool,value>::type type;
};
//--- A tester - requires T has member function name... just for now...
struct IsAB_BaseOf
{
template <class T>
static void test(T&& value)
{
return test(std::forward<T>(value),
typename AB_is_base_of<T>::type());
}
private: template <class T>
static void test(T&& value, std::true_type)
{
std::cout << value.name() << " derives from both A and B" << std::endl;
}
private: template <class T>
static void test(T&& value, std::false_type)
{
std::cout << value.name() << " does not derive from both A and B" << std::endl;
}
};
template <class T>
bool ab_IsBaseOf( T&& type )
{
return AB_is_base_of<T>::value;
}
int main() {
assert(!ab_IsBaseOf(An<0>()));
assert(!ab_IsBaseOf(Bn<0>()));
assert(!ab_IsBaseOf(Bn<0>()));
assert(!ab_IsBaseOf(An<0>()));
assert(!ab_IsBaseOf(An<0>()));
assert(!ab_IsBaseOf(Bn<0>()));
assert(ab_IsBaseOf(AnBn<0>()));
assert(ab_IsBaseOf(AnBm<0,1>()));
IsAB_BaseOf::test(AnBm<0,1>());
IsAB_BaseOf::test(An<0>());
IsAB_BaseOf::test(Bn<0>());
}
Output:
A0B1 derives from both A and B
A0 does not derive from both A and B
B0 does not derive from both A and B
基本上:
- 创建一个元函数,用于确定 A 和 B 何时是 T 的基数。
- 创建函数模板帮助程序以调用元函数
同心(ab_IsBaseOf)。 - 创建继承结构并测试...
这个想法是,如果 A 和 B 是 T 的底,则ab_IsBaseOf返回 true。
编辑:
人们可以毫不费力地从元函数创建一个类型,您可以将其用作函数的参数,该函数仅在 T 属于正确类型时才被调用(称为标记调度)。
编辑:
我现在修改了呈现的源代码,以使用标签调度根据类型 T 是否派生自 A 和 B 来选择一个函数,根据我的理解,这是 OP 想要的。欢迎提问。
相关文章:
- 如何在类列表中获取参考?
- 虚拟基类的派生类列表
- 流运算符和多态基类列表
- 在类列表上迭代
- 从其基类列表中调用重写的函数
- 在模板类列表/节点程序中获取错误
- 子类列表"master copies",寻找更好的设计
- 将子类列表转换为超类列表
- 使用值为 std::shared_ptr的映射是具有多索引类列表的良好设计选择
- 在模板基类列表中使用类本地类型别名
- 值不会在类列表的向量中被修改
- C++传递包含子类元素的类列表
- 迭代子类列表错误
- C++基类列表以及如何确定类类型
- Boost.Python:来自 python 中C++对象:无法添加到基类列表中C++
- 如何访问私有类列表
- 构造由索引从类列表中选择的类,c++
- 错误:"类列表"<RGBApixel>没有名为"curr"链表的成员
- 用于可变模板的基类列表
- 类设计以避免需要基类列表