У меня есть следующий код, который просто не компилируется, особенно после его пересылки через 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, если выполняются некоторые условия, мы можем просто вызвать переданную функцию, но не после того, как она будет перенаправлена в другую шаблонную функцию?
Со всеми этими шаблонами и 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
-Член).
Других решений пока нет …