2009-06-14 5 views
2

Приведенный ниже код не компилируется в Visual C++ 2005.C2228 Ошибка при построении подталкивание :: объект функции в списке аргументов конструктора

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 или создает импульс: : function object вне списка аргументов, который он компилирует.

SomeClass sc((boost::function<void()>(&someFunc))); 
    // or 
    boost::function<void()> f(&someFunc); 
    SomeClass sc(f); 

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

ответ

1

Это объявление функции для функции, ссылающейся на 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, резолюция состоит в том, чтобы рассмотреть любую конструкцию, которая может быть объявлением декларацией. [Примечание: объявление может быть явно устранено с помощью неэффективного стиля при помощи a = для указания инициализации или путем удаления избыточных круглых скобок вокруг имени параметра. ]

Обратите внимание, что для управления приоритетом, вам разрешается вводить круглые скобки примерно где-нибудь, как в следующем

int (((((((a))))))) = 3; 
int (*(pa)) = &a;