C++专业化、type_of 或只是 typeid

发布于 2024-08-07 14:06:25 字数 859 浏览 6 评论 0原文

我想知道在我的情况下使用什么更好以及为什么。首先我听说使用 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(我听到的是不好的)并在示例中实现这 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 检查。

I would like to know what is better to use in my situation and why. First of all I heard that using RTTI (typeid) is bad. Anyone could explain why? If I know exactly types what is wrong to compare them in a runtime? Furthermore is there any example how to use boost::type_of? I have found none searching through the mighty google :) Other solution for me is specialization, but I would neet to specialize at least 9 types of new method. Here is an example what I need:

I have this class

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

  }

So I need to rather check in typeid(what is I heard is BAD) and make these 3 realizations in example like:

 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
   }

So what is the best solution? I don't want to specialize for all A,B,C, because every type is has 3 specializations so I will get 9 methods or just this typeid check.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

倾`听者〃 2024-08-14 14:06:25

这很糟糕,因为

  1. A、B 和 C 在编译时是已知的,但您使用的是运行时机制。如果您调用 typeid,编译器将确保将元数据包含到对象文件中。
  2. 如果将“执行与 A 类型相关的这段代码”替换为使用 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

It's bad because

  1. A, B and C are known at compile-time but you're using a runtime mechanism. If you invoke typeid the compiler will make sure to include metadata into the object files.
  2. If you replace "Do this chunk of code related to A type" with actual code that makes use of CSomeClass's interface you'll see you won't be able to compile the code in case A!=CSomeClass and A having an incompatible interface. The compiler still tries to translate the code even though it is never run. (see example below)

What you normally do is factoring out the code into separate function templates or static member functions of classes that can be specialized.

Bad:

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
}

Better:

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)
}

Cheers, s

软甜啾 2024-08-14 14:06:25

一般来说,无需 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”。

Well generally solutions can be come up with without RTTI. It "can" show you haven't thought the design of the software out properly. THAT is bad. Sometimes RTTI can be a good thing though.

None-the-less there IS something odd in what you want to do. Could you not create an interim template designed something like as follows:

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

then partially specialise for the functions you want to as follows:

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

Then in your class define above you would do something such as ...

template

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

  }

This way it only actually does something in the "DoSomething" call if it is going through the partially specialised template.

要走就滚别墨迹 2024-08-14 14:06:25

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

好处

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_ 缺失的重载,您必须编写该重载。在第一个变体中可以忘记这一点。

The problem lies in the code chunks you write for every specialization.

It doesn't matter if you write (lengthwise)

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
}

or

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

The upside of the second case is, when you add a class D, you get reminded by the compiler that there is an overload for foo_ missing which you have to write. This can be forgotten in the first variant.

分开我的手 2024-08-14 14:06:25

恐怕这从一开始就行不通。即使类型不是 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
}

I'm afraid this is not going to work in the first place. Those "chunks of code" have to be compilable even if the type is not CSomeClass.

I don't think type_of is going to help either (if it is the same as auto and decltype in C++0x).

I think you could extract those three chunks into separate functions and overload each for CSomeClass. (Edit: oh there are else if's. Then you might indeed need lots of overloads/specialization. What is this code for?)

Edit2: It appears that your code is hoping to do the equivalent of the following, where int is the special type:

#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
}
可是我不能没有你 2024-08-14 14:06:25

我认为你的抽象在某些地方是错误的。

我会尝试重新定义A、B& C 就其需要公开的接口而言(C++ 中具有纯虚方法的抽象基类)。

模板基本上允许鸭子类型,但听起来 CFoo 对 AB 和 AB 知道得太多了。 C类。

typeid 不好是因为:

  1. typeid 可能很昂贵、臃肿
    二进制文件,携带额外的
    不应该的信息
    必需的。
  2. 并非所有编译器都支持它,
  3. 这基本上破坏了类层次结构。

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

I think you've got your abstractions wrong somewhere.

I would try redefining A, B & C in terms of interfaces they need to expose (abstract base classes in C++ with pure virtual methods).

Templating allows basically duck-typing, but it sounds like CFoo knows too much about the A B & C classes.

typeid is bad because:

  1. typeid can be expensive, bloats
    binaries, carries around extra
    information that shouldn't be
    required.
  2. Not all compilers support it
  3. It's basically breaking the class hierarchy.

What I would recommend is refactoring: remove the templating, instead define interfaces for A, B & C, and make CFoo take those interfaces. That will force you to refactor the behaviour so the A, B & C are actually cohesive types.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文