C ++模板歧义

时间:2020-03-05 18:50:14  来源:igfitidea点击:

我和一个朋友正在讨论C ++模板。他问我该怎么办:

#include <iostream>

template <bool>
struct A {
    A(bool) { std::cout << "bool\n"; }
    A(void*) { std::cout << "void*\n"; }
};

int main() {
    A<true> *d = 0;
    const int b = 2;
    const int c = 1;
    new A< b > (c) > (d);
}

main的最后一行有两个合理的解析。是'b'是模板参数,还是'b>(c)`是模板参数?

虽然,将其编译并查看我们得到的结果是微不足道的,但我们想知道是什么解决了歧义?

解决方案

回答

在没有括号的情况下,词法分析器的贪婪程度可能是决定因素,以使其清楚。我想这个词法学家不是贪婪的。

回答

AFAIK将其编译为new A &lt;b>(c)> d。这是解析它的唯一合理的方法恕我直言。如果解析器在正常情况下不能假设>结束模板参数,那将导致更多的歧义。如果我们想要另一种方式,则应该编写以下内容:

new A<(b > c)>(d);

回答

C ++标准定义,如果模板名称后跟一个<<,则<<始终是模板参数列表的开始,而第一个非嵌套的>则被视为模板参数列表的末尾。

如果我们希望将>运算符的结果作为模板参数,则需要将表达式括在括号中。如果参数是static_cast &lt;>或者另一个模板表达式的一部分,则不需要括号。

回答

如Leon&Lee所述,14.2 / 3(C ++ '03)明确定义了这种行为。

C ++'0x使用适用于>> >>的类似规则增加了乐趣。基本概念是,在解析模板参数列表时,非嵌套的>>将被视为两个不同的>>>标记,而不是正确的shift运算符:

template <bool>
struct A {
  A(bool);
  A(void*);
};

template <typename T>
class C
{
public:
  C (int);
};

int main() {
    A<true> *d = 0;
    const int b = 2;
    const int c = 1;
    new C <A< b  >>  (c) > (d); // #1
    new C <A< b > >  (c) > (d); // #2
}

上面的'#1'和'#2'是等效的。

当然,这可以解决在嵌套专业化中必须添加空格的烦恼:

C<A<false>> c;  // Parse error in C++ '98, '03 due to "right shift operator"