c++:传达可以使用的允许类的列表

c++: Communicating a list of allowed classes which can be used

本文关键字:许类 列表 可以使 c++      更新时间:2023-10-16

我有两组类,比如集合A = {a1, a2, a3}都派生自AsuperB = {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 想要的。欢迎提问。