2

我想知道在我的情况下使用什么更好以及为什么。首先我听说使用 RTTI (typeid) 很糟糕。任何人都可以解释为什么?如果我确切地知道类型在运行时比较它们有什么问题?此外,是否有任何示例如何使用 boost::type_of?我没有通过强大的谷歌搜索:) 对我来说其他解决方案是专业化,但我需要专门化至少 9 种新方法。这是我需要的一个例子:

我有这门课

  template<typename A, typename B, typename C>
  class CFoo
  {
     void foo()
     {
       // Some chunk of code depends on old A type
     }

  }

所以我需要检查 typeid(我听到的是 BAD)并在示例中进行这 3 个实现,例如:

 void foo()
   {
      if (typeid(A) == typeid(CSomeClass)
       // Do this chunk of code related to A type
      else
      if (typeid(B) == typeid(CSomeClass)
       // Do this chunk of code related to B type
      else
      if (typeid(C) == typeid(CSomeClass)
       // Do this chunk of code related to C type
   }

那么最好的解决方案是什么?我不想专门针对所有 A、B、C,因为每种类型都有 3 个专门化,所以我会得到 9 种方法或者只是这个 typeid 检查。

4

5 回答 5

6

这很糟糕,因为

  1. A、B 和 C 在编译时是已知的,但您使用的是运行时机制。如果您调用 typeid,编译器将确保将元数据包含到目标文件中。
  2. 如果您将“Do this chunk of code related to A type”替换为使用 CSomeClass 接口的实际代码,您会发现如果 A!=CSomeClass 和 A 具有不兼容的接口,您将无法编译代码。即使从未运行,编译器仍会尝试翻译代码。(见下面的例子)

您通常所做的是将代码分解为单独的函数模板或可以专门化的类的静态成员函数。

坏的:

template<typename T>
void foo(T x) {
    if (typeid(T)==typeid(int*)) {
        *x = 23; // instantiation error: an int can't be dereferenced
    } else {
        cout << "haha\n";
    }
}
int main() {
    foo(42); // T=int --> instantiation error
}

更好的:

template<typename T>
void foo(T x) {
    cout << "haha\n";
}
void foo(int* x) {
    *x = 23;
}
int main() {
    foo(42); // fine, invokes foo<int>(int)
}

干杯,s

于 2009-10-07T10:01:53.017 回答
4

好吧,通常可以在没有 RTTI 的情况下提出解决方案。它“可以”表明您没有正确考虑软件的设计。那很不好。不过,有时 RTTI可能是件好事。

尽管如此,你想做的事情还是有些奇怪。您能否创建一个临时模板,其设计如下:

template< class T > class TypeWrapper
{
  T t;
public:
  void DoSomething()
  {
  }
};

然后部分专门用于您想要的功能,如下所示:

template<> class TypeWrapper< CSomeClass >
{
  CSomeClass c;
public:
  void DoSomething()
  {
     c.DoThatThing();
  }
};

然后在你上面的类中定义你会做一些事情,比如......

模板

  class CFoo
  {
     TypeWrapper< A > a;
     TypeWrapper< B > b;
     TypeWrapper< C > c;
     void foo()
     {
       a.DoSomething();
       b.DoSomething();
       c.DoSomething();
     }

  }

这样,如果它通过部分专用模板,它只会在“DoSomething”调用中实际执行某些操作。

于 2009-10-07T10:02:30.290 回答
2

问题在于您为每个专业编写的代码块。

写(纵向)没关系

void foo()
{
   if (typeid(A) == typeid(CSomeClass)
    // Do this chunk of code related to A type
   else
   if (typeid(B) == typeid(CSomeClass)
    // Do this chunk of code related to B type
   else
   if (typeid(C) == typeid(CSomeClass)
    // Do this chunk of code related to C type
}

或者

void foo()
{
   A x;
   foo_( x );
   B y;
   foo_( y );
   C z;
   foo_( z );
}
void foo_( CSomeClass1& ) {}
void foo_( CSomeClass2& ) {}
void foo_( CSomeClass3& ) {}

第二种情况的好处是,当您添加一个 D 类时,编译器会提醒您,您必须编写 foo_missing 的重载。这可以在第一个变体中被遗忘。

于 2009-10-07T10:02:51.143 回答
2

恐怕这首先是行不通的。即使类型不是 CSomeClass,那些“代码块”也必须是可编译的。

我认为 type_of 也无济于事(如果它与 C++0x 中的 auto 和 decltype 相同)。

我认为您可以将这三个块提取到单独的函数中,并为 CSomeClass 重载每个块。(编辑:哦,有else if's。那么你可能确实需要很多重载/专业化。这段代码是做什么用的?)

Edit2:您的代码似乎希望执行以下等效操作,其中 int 是特殊类型:

#include <iostream>

template <class T>
bool one() {return false; }

template <>
bool one<int>() { std::cout << "one\n"; return true; }

template <class T>
bool two() {return false; }

template <>
bool two<int>() { std::cout << "two\n"; return true; }

template <class T>
bool three() {return false; }

template <>
bool three<int>() { std::cout << "three\n"; return true; }

template <class A, class B, class C>
struct X
{
    void foo()
    {
        one<A>() || two<B>() || three<C>();
    }
};

int main()
{
    X<int, double, int>().foo(); //one
    X<double, int, int>().foo();  //two
    X<double, double, double>().foo(); //...
    X<double, double, int>().foo(); //three
}
于 2009-10-07T10:03:03.610 回答
1

我认为您的抽象在某处有误。

我会尝试根据需要公开的接口重新定义 A、B 和 C(使用纯虚方法的 C++ 中的抽象基类)。

模板基本上允许进行鸭式输入,但听起来 CFoo 对 AB 和 C 类了解太多了。

typeid 不好,因为:

  1. typeid 可能很昂贵,会使二进制文件膨胀,携带不需要的额外信息。
  2. 并非所有编译器都支持它
  3. 它基本上打破了类层次结构。

我推荐的是重构:删除模板,改为为 A、B 和 C 定义接口,并让 CFoo 采用这些接口。这将迫使您重构行为,因此 A、B 和 C 实际上是内聚类型。

于 2009-10-07T10:02:08.683 回答