下面的代码无法在Visual C ++ 2005中编译。
class SomeClass {
public: boost::function<void()> func;
SomeClass(boost::function<void()> &func): func(func) { }
};
void someFunc() {
std::cout << "someFunc" << std::endl;
}
int main() {
SomeClass sc(boost::function<void()>(&someFunc));
sc.func(); // error C2228: left of '.func' must have class/struct/union
return 0;
}
如果我将括号放在SomeClass构造函数的参数周围,或者在参数列表之外构造boost :: function对象,那么编译就可以了。
SomeClass sc((boost::function<void()>(&someFunc)));
// or
boost::function<void()> f(&someFunc);
SomeClass sc(f);
以前的代码有什么问题?
答案 0 :(得分:1)
这是一个函数声明,用于引用boost:function <void()>
并返回SomeClass
的函数。您可以记住以下规则,结果适用于许多其他此类消除歧义的情况。您可以在C ++标准的8.2
部分找到这些案例的描述。
任何可能是声明的构造都将被视为声明
这意味着,以下将作为参数声明,带有多余的括号
boost::function<void()>(&someFunc)
如果删除括号,这将变得清晰
boost::function<void()> &someFunc
因此,整个声明将不再声明一个对象,而是一个函数
SomeClass sc(boost::function<void()> &someFunc);
要修复它,请使用强制转换符号
SomeClass sc((boost::function<void()>)&someFunc);
或者将括号括在整个表达式中,就像你一样。
以下是来自8.2
的所有荣耀的标准:
函数式转换与6.8中提到的声明之间的相似性所产生的歧义也可能出现在声明的上下文中。在该上下文中,选择在函数声明与参数名称周围的冗余括号集和具有函数样式转换作为初始化器的对象声明之间。正如6.8中提到的含糊不清一样,该决议是考虑任何可能是声明声明的结构。 [注意:声明可以通过非函数式转换显式消除歧义,通过a表示初始化或删除参数名称周围的冗余括号。 ]
请注意,为了控制优先级,您可以在任何地方引入括号,如下所示
int (((((((a))))))) = 3;
int (*(pa)) = &a;
答案 1 :(得分:0)
这被称为“C ++的最令人烦恼的解析”(来自a book by Scott Meyers called Effective STL)。
作为answered above,编译器更喜欢将有问题的行解释为函数声明。