2

下面的代码不能在 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);

之前的代码有什么问题?

4

2 回答 2

1

它是一个函数的函数声明,它引用 aboost:function <void()>并返回 a SomeClass。您可以记住以下规则,该规则适用于许多其他此类消歧案例。8.2您可以在 C++ 标准部分找到这些情况的描述。

任何可能是声明的构造都将被视为声明

这意味着,以下将被视为参数声明,带有多余的括号

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 中提到的歧义一样,解决方案是将任何可能是声明的构造视为声明。[注意:声明可以通过非函数式强制转换、= 表示初始化或删除参数名称周围的冗余括号来明确消除歧义。]

请注意,为了控制优先级,您可以在任何地方引入括号,如下所示

int (((((((a))))))) = 3;
int (*(pa)) = &a;
于 2009-06-14T12:53:08.970 回答
0

这被称为“C++ 最令人烦恼的解析”(来自Scott Meyers 的一本书,名为 Effective STL)。

如上所述,编译器更喜欢将有问题的行解释为函数声明。

于 2009-06-14T12:32:34.777 回答