Ошибка C2228 при создании объекта boost :: function в списке аргументов конструктора - PullRequest
2 голосов
/ 14 июня 2009

Код ниже не компилируется в 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);

В чем проблема с предыдущим кодом?

Ответы [ 2 ]

1 голос
/ 14 июня 2009

Это объявление функции для функции, принимающей ссылку на boost:function <void()> и возвращающей 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;
0 голосов
/ 14 июня 2009

Это известно как «Самый невероятный синтаксический анализ C ++» (из книги Скотта Мейерса под названием Effective STL ).

Как ответил выше , компилятор предпочитает интерпретировать проблемную строку как объявление функции.

...