0

当我发现创建模板类的这种依赖于预处理器的方法时,我只是在搞砸:

#include <iostream>
#include <typeinfo>

// Is this a valid template class?
#define TEMPLATE_CLASS(T)\
class TemplateClass_ ## T\
{\
private:\
    T value;\
public:\
    void print_type()\
    {\
        std::cout << typeid(T).name() << std::endl;\
    }\
}

class Sample {};

TEMPLATE_CLASS(int) obj1;
TEMPLATE_CLASS(char) obj2;
TEMPLATE_CLASS(Sample) obj3;

int main(int argc, char* argv[])
{
    obj1.print_type();
    obj2.print_type();
    obj3.print_type();
}

我简单地编译了这个:

g++ src.cpp -o main.exe

输出:

i
c
6Sample

现在,如您所见,它的工作方式与模板类几乎相同。除了一个明显的事实之外,对象只能在全局范围内声明,因为它实际上在您使用时定义了一个新类 inline TEMPLATE_CLASS(T),而新类不能在函数中定义。对此的解决方案可以是:

TEMPLATE_CLASS(float);

int main() { TemplateClass_float obj; }

不管怎样,这给了我很多思考。首先,这甚至可以称为有效的泛型类吗?那么,它可以用来代替标准模板功能吗?显然,使用标准模板功能要方便得多,但我的意思是,这也可以吗?最后,由 C++ 标准定义的模板功能是否在内部执行类似于我对预处理器所做的事情?如果不是,这个实现和 C++ 的标准模板特性有什么区别?

4

4 回答 4

7

它仅在最简单的情况下与模板执行相同的操作。尝试使用宏执行此操作:

template <class Ty> class C {};
template <class Ty> class C<Ty*> {};
template <class Ty> class C<std::vector<Ty> > {};
于 2012-08-14T11:52:02.753 回答
3

你所做的不是templates,而是macros。使用宏而不是模板是一个很好的方法来射击自己。这是一个例子msdn

//macro
#define min(i, j) (((i) < (j)) ? (i) : (j))

//template
template<class T> T min (T i, T j) { return ((i < j) ? i : j) }

以下是宏的一些问题:

  1. 编译器无法验证宏参数的类型是否兼容。宏在没有任何特殊类型检查的情况下展开。

  2. i 和 j 参数被评估两次。例如,如果任一参数具有后增量变量,则增量执行两次。

  3. 因为宏是由预处理器扩展的,所以编译器错误消息将引用扩展的宏,而不是宏定义本身。此外,宏将在调试期间以扩展形式显示。

于 2012-08-14T11:50:31.680 回答
3

预处理器可用于创建宏,如果您使用的是 C,您可能会使用它来完成您所做的事情。C++ 提供模板作为语言的一部分,因此您可以执行此操作等等。例如,您的宏不会是强类型的,您将错过大量编译时检查,这可能会发现预处理器永远不会发现的错误。

几乎在所有情况下都使用宏而不是模板不是可行的方法。您的代码也将难以维护,因此难以遵循。所以,换一种说法,如果你想让你的同事少看你,并且对提到你的名字感到恼火,那就继续使用宏。:)

于 2012-08-14T11:55:28.290 回答
1

好吧,它混淆了类的实际类型,从而使使用函数等变得更加困难。而且您似乎不能在您的方法中使用模板递归,因为每次使用该宏时它都会定义新类。除此之外,您无法使其图灵完备,因为您无法为模板类定义异常情况。它还缺乏定义基于值的模板类的能力:DI 认为您可以轻松列出更多问题,但这些可能是主要问题。

于 2012-08-14T11:51:28.193 回答