我有以下代码无法编译,特别是在通过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”之前,如果满足某些条件,我们可以只调用传入的函数,而不能在将其转发到另一个模板函数之后调用?
答案 0 :(得分:1)
有了所有这些模板和auto
声明,就很容易忘记要处理的数据类型。让我们从代码底部开始:
auto myFunc = std::bind( &TestChild::thisTestOk, this );
什么是myFunc
?虽然正式未指定std::bind
的返回类型,但已指定其使用方式(例如,参见cppreference.com)。将此返回值作为函数调用等效于调用thisTestOk()
并将其唯一参数绑定到this
。
也就是说,TestChild
的所有非静态成员函数中存在的指向TestChild
的隐藏指针参数已由this
替换,其效果是将成员函数转换为非成员函数的过程。现在,让我们看看如何调用该包装器的非成员函数。
在test()
中,此包装器通过return fn()
调用。它是作为一个函数调用的,并且可以按预期工作。
在testAtNextLevel()
中,此包装器通过this->*fn()
调用。这个包装器 non-member 函数被调用为指向成员函数的指针,这是一个错误。为了使它在语法上起作用,应该像在fn()
中那样简单地调用test()
。如果您确实想覆盖绑定的对象并使用this
作为fn()
的隐藏参数,则需要传递不同的参数作为testAtNextLevel()
的参数,可能是指向成员的指针(并且它必须是指向TestParent
成员的指针,而不是指向TestChild
成员的指针)。