std :: forward для пересылки функции - PullRequest
0 голосов
/ 07 ноября 2018

У меня есть следующий код, который просто не компилируется, особенно после его пересылки через std :: forward

struct TestParent
{
    template< typename Fn >
    bool test( Fn&& fn )
    {
        //.. do something
        //.. check some condition
        bool someCondition = true;
        if ( someCondition )

        {
            //this call works!
            return fn();
        }

        return testAtNextLevel( std::forward< Fn >( fn ) );
    }

    template < typename Fn >
    bool testAtNextLevel( Fn&& fn )
    {
        if ( (this->*fn() )
        {
             return true;
        }

         //... test some more
         return true;
     }
}

struct TestChild: public TestParent
{
     bool thisTestOk();
     bool testAll();
}

bool TestChild::thisTestOk()
{
     return true;
}

bool testAll()
{
    auto myFunc = std::bind( &TestChild::thisTestOk, this );
    return test( myFunc );
}

При компиляции я получил это сообщение об ошибке:

error: no match for 'operator->*' (operand types are 'TestParent*' and 'std::_Bind<std::_Mem_fn<bool (TestChild::*)()>(TestChild*)>')
 if ( (this->*fn)() )

У кого-нибудь есть идеи относительно того, почему после прохождения std :: forward функция просто не может быть вызвана? В базовом классе, прямо перед вызовом testAtNextLevel, если выполняются некоторые условия, мы можем просто вызвать переданную функцию, но не после того, как она будет перенаправлена ​​в другую шаблонную функцию?

1 Ответ

0 голосов
/ 08 ноября 2018

Со всеми этими шаблонами и объявлениями auto становится легко потерять отслеживание того, с каким типом данных вы имеете дело. Давайте начнем с нижней части вашего кода:

auto myFunc = std::bind( &TestChild::thisTestOk, this );

Что такое myFunc? Хотя тип возвращаемого значения std::bind официально не указан, его использование указано (см., Например, cppreference.com ). Вызов этого возвращаемого значения как функции эквивалентен вызову thisTestOk() с единственным аргументом, связанным с this.

То есть скрытый аргумент указателя на TestChild (присутствующий во всех нестатических функциях-членах TestChild) был заменен на this, что приводит к преобразованию функции-члена в функция, не являющаяся членом. Теперь давайте посмотрим, как вы вызываете эту функцию, не являющуюся членом оболочки.

В test() эта оболочка вызывается через return fn(). Он вызывается как функция и работает по назначению.

В testAtNextLevel() эта оболочка вызывается через this->*fn(). Эта обертка не-член вызывается как функция указатель на член, что является ошибкой. Чтобы это работало синтаксически, вызов должен быть просто fn(), как это было в test(). Если вы действительно хотите переопределить связанный объект и использовать this в качестве скрытого аргумента для fn(), вам нужно передать что-то другое в качестве аргумента testAtNextLevel(), возможно, указатель на член (и это должно было бы быть указателем на TestParent члена, а не указателем на TestChild члена).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...