宏就是将代码展开,也就是将宏的代码复制,然后在预编译期间在使用的地方展开,宏本身不会对代码进行检查,只管展开,可能会产生各种各样的矛盾。当遇上可能需要类型不一样,但是代码重复的时候就可以考虑用宏,一个简单的例子,

#define test(a){\
  if(a>0)\
    a+1 \
}

在段代码,在C++里,无论是int,float,double,char类型的变量都能传进去用,如果写成函数,那么可能需要写几个重载函数,当然也可以写成模板。
复杂的例子,比如一个类的所有子类对象,添加到一个std::vector<父类>里,如:

std::vector<ComponentClass> componentClass;
#define ADD_COMPONENTCLASS_FUNCTION(MyComponentClass){ \
auto componentClass = generateInstrumentComponentClass<MyComponentClass>(); //2
m_componentClassies.emplace_back(componentClass); \ //3
}

如果有很多子类类型,可能需要一直重复写2~3的代码,但是也可以这样简写成宏,后面只需要执行:

ADD_COMPONENTCLASS_FUNCTION(子类类型);

这一行代码就行了

同样地,模板也是在编译器将代码展开,不过模板在单独编译本文件(hpp或cpp)时就会对自身所在文件进行代码的类型检查,模板里,而不是像宏,宏只是预编译时一一展开,没有类型检查。模板可以看下这篇文章:https://www.cnblogs.com/aademeng/articles/7263785.html