Как получить адрес функции-члена для локального класса, определенного в функции (C ++) - PullRequest
3 голосов
/ 28 января 2010

Я пытаюсь сделать следующее: Получить адрес функции-члена из класса, который был локально определен внутри функции.

class ConnectionBase
{
};

template class<EventType, SinkType>
class ConnectionImpl : public ConnectionBase
{
public:
typedef void (SinkType::*EventCallback)(EventType const&);
};


template<class EventType>
class Source
{
    template <class SinkType>
    boost::shared_ptr<ConnectionBase> setupCallback(typename ConnectionImpl<EventType, SinkType>::EventCallback func, SinkType* sink)
    {
    // do the actual connecting.
    }
};

class SomeClass
{
public:
    void someFunction(int const& event){}
}

class SomeUnitTest
{
public:
    void someTest()
    {
        class NestedClass 
        {
        public:
            void someFunction(int const& event){}
        };

       NestedClass nc;

       //Try#1 - This does not work
       setupCallback<int, NestedClass>(&NestedClass::someFunction, &nc);

       //Try #2 - This also does not work
       setupCallback<int, NestedClass>(&SomeUnitTest::someTest::NestedClass::someFunction, &nc);

       //Try #3 - Following the GCC error output, I tried this
       setupCallback<int, NestedClass>(&SomeUnitTest::someTest()::NestedClass::someFunction, &nc);

       SomeClass sc;

       //This works fine, as expected
       setupCallback<int, SomeClass>(&SomeClass::someFunction, &sc);

    }
};

Попробуй №2 и №3, совершенно запутав GCC, он понятия не имеет, что я пытаюсь сделать. Попытка №1 выдает более полезное сообщение об ошибке, в котором говорится, что setupCallback не существует, который принимает форму «setupCallback (void (SomeUnitTest :: someTest () :: NestedClass :: SomeFunction :: *) и т. Д.) Вот как родилась попытка № 3.

Я не могу найти много информации о классах, определенных внутри функции, кто-нибудь знает правильный синтаксис для этого и, возможно, есть ресурс, который обсуждает эту тему?

Хорошо, похоже, все решено, как отмечали оба автора, у местных классов нет связи, это не может работать. Теперь, зная это, я нашел эту статью, в которой обсуждается это для всех, кто сталкивается с этой проблемой и сталкивается с этим вопросом: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=420

Edit: Разъяснение setupCallback (), рабочий пример с более обычным классом
Изменить № 2: Обновлена ​​формулировка для изменения "вложенного" на "локальный". Добавлено больше подробностей для setupCallback.
Редактировать № 3: Добавлены ссылки на дополнительную информацию. Спасибо всем.

Ответы [ 2 ]

4 голосов
/ 28 января 2010

Ваш первый вариант является правильным, если рассматривается конкретный вопрос взятия адреса. Нет ограничений по получению адреса функций-членов локальных классов. Правильный синтаксис обычный

&NestedClass::someFunction

и все. Вы можете попробовать сохранить его в промежуточном указателе в вашем коде

void (NestedClass::*ptr)() = &NestedClass::someFunction;

и я уверен, что ваш компилятор примет это.

Однако проблема, которая, как я подозреваю, существует в вашем коде, не имеет абсолютно никакого отношения к правильному способу получения адреса функции-члена. Это скорее способ объявления первого параметра setupCallback. Поскольку вы говорите, что он работает с &SomeClass::someFunction в качестве первого аргумента, я ожидаю, что setupCallback будет объявлено как

void setupCallback(void (SomeClass::*cb)(), SomeClass *p); // one possibility

т.е. жестко запрограммирован , чтобы ожидать указатель на член SomeClass в частности. Вместо этого вы не можете указать указатель на член NestedClass. NestedClass совершенно не связан с SomeClass, а указатели на члены NestedClass полностью несовместимы с указателями на члены SomeClass. Вот почему он не скомпилируется.

Если вы что-то нам не показываете (например, setupCallback может быть шаблоном функции? Или перегружен для разных типов параметров?), То, что вы пытаетесь сделать, просто невозможно достичь независимо от того, как вы берете адрес члена До тех пор, пока NestedClass не имеет отношения к SomeClass. Функция setupCallback предназначена для работы только с SomeClass и SomeClass.

Укажите дополнительную информацию о setupCallback. Как это объявлено?

Обратите внимание, что если setupCallback объявлен как шаблон функции, параметризованный типом класса, как в

template <class T> void setupCallback(void (T::*cb)(), T* p);

тогда вы не сможете использовать локальный класс NestedClass в качестве аргумента шаблона для параметра T. В этом случае тот факт, что ваш NestedClass не имеет связи, действительно вступает в игру. Но, опять же, это не имеет ничего общего с получением адреса члена, а скорее связано с тем, что классы без связи не могут использоваться в качестве аргументов шаблона в C ++.

4 голосов
/ 28 января 2010

Я не знаю о проблеме синтаксиса, должны применяться обычные правила доступа, но здесь есть другая проблема, если это сработает, поскольку эти функции-члены не имеют связи.
Чтобы вообще принимать локальные типы, setupCallback() должна быть функцией шаблона, но аргументы типа шаблона без связи не допускаются.

§3.5 / 8 говорит:

Имена, не охваченные этими правилами, имеют нет связи. Более того, кроме как отмечено, имя объявлено в локальной области (3.3.2) не имеет связи.

Члены местных классов там не охвачены. §9.3 / 3 уточняет, что:

Функции-члены локального класса (9.8) не имеют связи.

Короче говоря: не используйте функции-члены локального класса в качестве обратных вызовов, вместо этого используйте нелокальный класс.

...