I have the following code that just doesn't compile, particularly after it is being forwarded through 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 );
}
When compiling I got this error message:
error: no match for 'operator->*' (operand types are 'TestParent*' and 'std::_Bind<std::_Mem_fn<bool (TestChild::*)()>(TestChild*)>')
if ( (this->*fn)() )
Anyone has any ideas as to why after going through std::forward, the function just cannot be called? At the base class, right before the call 'testAtNextLevel', if some conditions is met we can just call the passed in function, but not after it is being forwarded to another template function?
With all of those templates and
auto
declarations, it becomes easy to lose track of what type of data you are dealing with. Let's start near the bottom of your code:What is
myFunc
? While the return type ofstd::bind
is officially unspecified, its use is specified (see, for example, cppreference.com). Invoking this returned value as a function is equivalent to invokingthisTestOk()
with its lone argument bound tothis
.That is, the hidden pointer-to-
TestChild
argument (present in all ofTestChild
's non-static member functions) has been replaced bythis
, which has the effect of converting a member function to a non-member function. Now let's look at how you invoke this wrapper non-member function.Within
test()
, this wrapper is invoked viareturn fn()
. It is invoked as a function, and works as intended.Within
testAtNextLevel()
, this wrapper is invoked viathis->*fn()
. This wrapper non-member function is invoked as a pointer-to-member-function, which is an error. To make it work syntactically, the invocation should be simplyfn()
, as it was intest()
. If you really want to override the bound object and usethis
as the hidden argument tofn()
, you need to pass something different as the argument totestAtNextLevel()
, probably a pointer-to-member (and it would have to be a pointer-to-TestParent
-member, not a pointer-to-TestChild
-member).