2009-10-07 30 views
2

我想知道什么是更好的使用我的情况,为什么。首先我听说使用RTTI(typeid)是不好的。任何人都能解释为什么如果我确切知道类型在运行时比较它们有什么问题?此外有什么例子如何使用boost :: type_of?我发现没有搜索强大的谷歌:)其他解决方案对我来说是专业化的,但我会neet专注于至少9种新方法。这里有一个例子我所需要的:C++专业化,type_of或只是typeid

我有这个类

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种方法或只是这种类型检查。

回答

6

这是不好的,因为

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

1

我觉得你有你的抽象错了地方。

我会尝试重新定义A,B & C的接口,他们需要公开(C++中的抽象基类,纯虚方法)。

模板化基本上允许鸭子打字,但它听起来像CFoo知道太多的关于C类的A B & C类。

typeid的是不好的,因为:

  1. typeid的可能是昂贵的,腌 二进制文件,进行不应该要求 有多余的 信息。
  2. 并非所有的编译器都支持它
  3. 它基本上破坏了类的层次结构。

我推荐的是重构:删除模板,而是为A,B & C定义接口,并使CFoo接受这些接口。这将迫使你重构行为,所以A,B实际上是内聚类型。

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”调用中执行某些操作。

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_丢失的重载。这可以在第一个变体中被遗忘。

2

恐怕这不会起作用。即使类型不是CSomeClass,那些“代码块”也必须是可编译的。

我不认为type_of会帮助(如果它是相同的自动和decltype在C++ 0x)。

我认为你可以将这三个块抽取为单独的函数,并为CSomeClass重载每个块。 (编辑:哦有else if's。那么你可能确实需要大量的过载/专业化。这是什么代码?)

编辑2:看起来你的代码希望做到以下等效,其中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 
}