今天说一下额外 () 产生不同意义的情况。

多数情况下,额外的()是不影响语义的,但在以下 5 种情况,有无 () 则意义不同,此时 () 就有了特殊的作用。

禁止 ADL

在「洞悉 C++ 函数重载决议」提到过,使用额外的 () 可以防止 ADL。

namespace N {
    struct S { };
    void f(S);
}

void g() {
    N::S s;
    f(s);   // OK: calls N::f
    (f)(s); // error: N::f not considered; parentheses
            // prevent argument-dependent lookup
}

这是因为,ADL 起作用的前提是 f 是一个 unqualified-id,而 (f) 是一个 primary expression,所以 ADL 被禁止了。

结合 decltype 判断 Value Categories

decltype(e) 得到的是变量名称的类型,decltype((e)) 得到的是表达式的类型。注意:lvalue, rvalue, prvalue 这些叫法是针对 expressions 的,而非 value。

因此可以利用 decltype((e)) 来判断 Value Categories。

std::string s {"text"};
auto&& str = std::move(s);

// The type of names
fmt::print("xvalue : {}\n", std::is_rvalue_reference_v<decltype(str)>);   // true
// The type of expressions
fmt::print("lvalue : {}\n", std::is_lvalue_reference_v<decltype((str))>); // true

解决 vexing parses problem

C++ 为了向后兼容 C,对象与函数声明解析会产生歧义,这个问题就称为 vexing parses。

一个例子:

void foo(double v) {
    int m(int(v)); // function declaration
    int n(int());  // function declaration
}

这里 mn 是函数声明,所以 Scott Meyers 称之为最令人迷惑的解析(most vexing parses)。

此处加上一个额外的括号就可以解决这个问题:

void foo(double v) {
    int m((int(v))); // object declaration
    int n((int()));  // object declaration
}

为什么可以呢?这是由于 C 的语法不允许 (variable) 里出现变量,只允许 (type) 里出现类型,而 C++ 的语法 (expression) 里期望出现的是表达式,于是在解析时便可将 C 的歧义排除,剩下的就是对象声明。

这也是为何 C++ 之后更推荐使用 uniform initialization 进行初始化的原因,这种初始化方式可以避免解析问题,真正做到一致性初始化(别提 vector:-\)。

comma operator

在逗号表达式中,() 会改变参数个数,因为它只会返回最右边的值。

例子:

f(a, (t=3, t+2), c); // 3 arguments, (a, t = 5, c)

Macros

在宏中加 () 已是老生常谈,这应该是 5 条中最广为熟知的一条。

#define TIMES_BAD(a, b) a * b
#define TIMES_GOOD(a, b) (a) * (b)
TIMES_BAD(1 + 2, 2 + 3);  // 8
TIMES_GOOD(1 + 2, 2 + 3); // 15

在宏中有逗号的情况下,也要多加一个 ()assert 宏是一个典型例子。

assert(std::is_same_v<int, int>);   // error: assert does not take two arguments
assert((std::is_same_v<int, int>)); // OK: one argument

Leave a Reply

Your email address will not be published. Required fields are marked *

You can use the Markdown in the comment form.