2

不是计算机科学背景,当涉及宏时,我对模板有点困惑:

考虑以下代码:

template <int Signal1, int Signal2>
void my_add(int & x, int y)
{
#if Signal1==1||Signal2==1
    x+=y;
#endif 
}

//And call the template, e.g.: my_add<1, 1>(x, 3);

问题是,#if宏似乎没有按预期工作,好像#if宏测试总是返回false,所以结果是my_add<1,1>什么都不做。

任何人都可以解释为什么会这样?( MSVC 2012)。

4

5 回答 5

4

这就是你真正想要的,这不是微不足道的:

template <bool defaultCase> class Adder
{
   static void my_add(int & x, int y) { }
};

template < > class Adder<true>
{
   static void my_add(int & x, int y) { x += y; }
};

template <int Signal1, int Signal2>
void my_add(int & x, int y)
{
   Adder<Signal1==1 || Signal2==1>::my_add(x,y);
}

这是一个部分特化,它需要一个类模板。函数模板没有部分特化,因为它会干扰重载,但这里的模板参数不参与重载。

于 2013-10-17T08:45:31.573 回答
1

您将模板使用的类型 Signal1/Signal2 与预处理器使用的符号常量混淆 - 两个不同的“域”。

在预处理阶段(实际编译之前)评估宏符号并使用符号。

模板类型是在编译阶段定义的(如果模板是实例化的。)

尽管您对两者使用相同的“名称”,但预处理器仍然没有定义任何 Signal1/2 符号。

以下链接可能会有所帮助: 预处理器指令

于 2013-10-17T08:34:14.133 回答
1

简而言之:模板是在编译时评估的,但是任何以它开头的#都是处理器语句,并且在编译代码之前就被评估。我希望你看到这两者不能按照你想要的方式混合。

在您的示例中,您正在比较令牌Signal11. Signal1现在,如果它本身是一个 makro 并根据某些条件设置其他位置以替换为 等,这将是有意义的,但事实并非1如此。2

于 2013-10-17T08:35:01.540 回答
0

宏不关心甚至不知道模板。宏只是通过搜索和替换源代码文件中的字符和行来工作,就在它即将被编译之前。

那时,没有变量有值,没有函数正在运行,也没有模板参数有值。这类似于 PHP 代码的预处理方式:底层 HTML 和 PHP 逻辑完全分开,不能交互。

这可能会令人困惑,因为您的宏代码看起来像是在函数模板“内部”,但实际上并非如此:这两个东西存在于不同的存在平面上!

当没有宏Signal1Signal2不存在时(这里大概就是这种情况),从预处理器获取输出然后用于处理的代码是这样的:

template <int Signal1, int Signal2>
void my_add(int & x, int y)
{
}
于 2013-10-17T08:40:44.977 回答
-2

宏无法获取类型信息。它在编译器之前调用。Signal1 和 Signal2 在您的宏中所指的内容与模板参数无关。

使用#define Signal1 1并将x+=y在您的模板中生效。请记住 - 这发生在根据您的使用情况扩展模板之前。

编辑:问题是关于部分专业化的。让这作为一个温和的“不要突然提出问题”的提醒。

于 2013-10-17T08:35:40.077 回答