mardi 31 mars 2015

I have a member function _wrapper in my class, that encapsulates some common logic around family of other functions. This wrapper function accepts pointer to function that is being wrapped and its arguments.


Wrapper in my class is implemented similar to how it is done in this example class Foo:



#include <functional>

class Foo
{
public:
void bar1(int a)
{
/// No-op.
}

void bar2(const int & a)
{
/// No-op.
}

void foo(int x)
{
_wrapper_bar1(x); /// No problems to deduce type
_wrapper_bar2(x); /// No problems to deduce type

_wrapper(&Foo::bar1, x); /// Deduction fails
_wrapper(&Foo::bar2, x); /// Deduction fails
}

private:
template <typename ...Args>
void _wrapper(void (Foo::*method) (Args ...), Args && ...args)
{
/// Do some common stuff here...

(this->*method(std::forward<Args>(args)...));
}

template <typename ...Args>
void _wrapper_bar1(Args && ...args)
{
bar1(std::forward<Args>(args)...);
}

template <typename ...Args>
void _wrapper_bar2(Args && ...args)
{
bar2(std::forward<Args>(args)...);
}
};

int main(int argc, char ** argv)
{
Foo().foo(123);
return 0;
}


When I pass an lvalue, foo's argument int x, to the wrapper, clang compiler complaints that there is a conflict and deduction fails:



test.cpp:21:9: error: no matching member function for call to '_wrapper'
_wrapper(&Foo::bar1, x); /// Deduction fails
^~~~~~~~
test.cpp:27:10: note: candidate template ignored: deduced conflicting types for parameter 'Args' (<int> vs. <int &>)
void _wrapper(void (Foo::*method) (Args ...), Args && ...args)
^
test.cpp:22:9: error: no matching member function for call to '_wrapper'
_wrapper(&Foo::bar2, x); /// Deduction fails
^~~~~~~~
test.cpp:27:10: note: candidate template ignored: deduced conflicting types for parameter 'Args' (<const int &> vs. <int &>)
void _wrapper(void (Foo::*method) (Args ...), Args && ...args)


The thing is I don't understand why is this happening. It is okay to pass just lvalue alone, as it is done using _wrapper_bar1 and _wrapper_bar2. And doing so does not rise any conflict of this sort, ie const T & vs T &.


I know a way around this error: by casting lvalue to an rvalue using std::move(x), but obviously it is not a fix, since move is not actually needed. Also, sometimes I need to use x after calling wrapper function, and using moved value is an UB.


Probably my template is very broken and I am missing some obvious thing. I'd appreciate your help.


Aucun commentaire:

Enregistrer un commentaire