Pass overloaded member function to a variadic template function - c++

I have a class with a function add:
class Pool {
public:
Pool() {};
template<class F, class... A>
auto add(F&& f, A&&... args) -> std::future<typename std::result_of<F(A...)>::type>
{
// return empty placeholder, for the sake of this code example
std::future<typename std::result_of<F(A...)>::type> ret;
return ret;
};
};
It should take any function with its arguments, add it to a thread pool and return a future of the result type of that function.
And a class where I use it:
class MyClass {
public:
string doIt(string) { return string("a"); };
string doIt(int, string) { return string("b"); };
void test() {
Pool myPool;
string a("test");
myPool.add(&MyClass::doIt, a); // Error
};
};
Which gives a compiler error:
Error 1 error C2914: 'Pool::add' : cannot deduce template argument as function argument is ambiguous MyClass.cpp 94
Now the problem is (I think) that the compiler can't deduce which overload I want to use. Similar to Overloaded function as argument of variadic template function.
(Also I'm not 100% clear on why I have to use "&" for class member functions, but no ampersand if I pass in a free function).
Anyway I also tried the workaround mentioned in above answer:
struct doIt_wrapper {
template <typename... T>
auto operator()(T... args) -> decltype(doIt(args...)) {
return doIt(args...);
}
};
and then modifying MyClass::test() to:
void test() {
Pool myPool;
string a("test");
myPool.add(doIt_wrapper(), a);
};
But it also gives me a compiler error:
error C2893: Failed to specialize function template 'unknown-type doIt_wrapper::operator ()(T...)' C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xrefwrap 58
I also tried a few variants like myPool.add(doIt_wrapper<string>() and with/without '&' but they all generate one or the other compiler error.
I think I don't fully understand the problem yet and I would be glad if someone could shed light on it. Also I am looking for a proper solution to this problem. It can't really be the case that this only works as long as there are no two functions with the same name, and as soon as there are, everything breaks down without a proper, generic solution?
Edit: Fixed a few typos and uploaded a minimal example here: http://ideone.com/eX1r1l

As others have mentioned, the problem is that doIt() is not callable inside the doIt_wrapper class as it also needs a pointer to the object called on.
You could just modify the doIt_wrapper operator() to also take a pointer to the object and pass a pointer to this as first argument to add().
It would then look something like this:
#include <iostream>
#include <future>
using namespace std;
class Pool {
public:
Pool() {};
template<class F, class... A>
auto add(F&& f, A&&... args) -> std::future<typename std::result_of<F&&(A&&...)>::type>
{
// return empty placeholder, for the sake of this code example
std::future<typename std::result_of<F&&(A&&...)>::type> ret;
return ret;
};
};
class MyClass {
public:
string doIt(string) { return string("a"); };
string doIt(int, string) { return string("b"); };
struct doIt_wrapper
{
template<class T, class... Ts>
auto operator()(T&& t, Ts&&... args) -> decltype(t->doIt(std::forward<Ts>(args)...))
{
return t->doIt(std::forward<Ts>(args)...);
}
};
void test() {
Pool myPool;
string a("test");
myPool.add(doIt_wrapper(), this, a); // No error no more
};
};
int main() {
// your code goes here
MyClass my;
my.test();
return 0;
}
This way you don't have to do the casts. The code compiles on both GCC and Clang.

You may use lambda:
myPool.add([this](const std::string& s) {doIt(s);}, a);
or even
myPool.add([this, a]() {doIt(a);});
Currently, you may indicate which overload to use that way:
myPool.add(static_cast<std::string (MyClass::*) (std::string)>(&MyClass::doIt), a);
Note that doIt is a method (not a free function or static function), so you have to call it with an object.
If you add static to doIt, you may choose the overload with
myPool.add(static_cast<std::string (*) (std::string)>(&MyClass::doIt), a);

The problem is that non-static member functions have a hidden, implicit this parameter that points to the instance that called it. Your compiler is right to reject it as it doesn't have the correct arguments for the function. Sending in this as an additional bound parameter will work:
myPool.add(&MyClass::doIt, this, a);
// ^^^^
Using a lamda expression will work as well.
Also, the standard library function std::async() already does what you're trying to do here, and more. Consider using that instead.
Edit: You also need to cast to the correct type to select the correct overload. #Jarod42 already shows you how.

Related

std::function - could not deduce template argument for ... (variadic template functions)

I'm writing a simple "wrapper library" around another library and I'm having issues with std::function not being able to deduce template arguments for variadic template functions. To make things more concrete:
There's a library (it's a HTTP server) that I'm planning to "expand" with more functionality and to make it more convenient to use by "other code users" (automatic serialization of data, writing controller functions based on needs etc.). Basically cutting down on a lot of boilerplate code. From now on I'm calling this one simply "library". It cannot be touched or changed.
There's the code that "expands" the functionality above that I write myself and it's where I have the problem. From now on I call this a "wrapper library".
There's the "user code", that is - any code that uses the "wrapper library". I've included examples what I'd like it to look like and I'd rather keep it as simple as possible, especially when it comes to unnecessary template parameters bloat (not having to explicitly pass template arguments when it can be deduced by the compiler etc.). See main in the code below for examples.
Here's the complete example (that doesn't compile):
#include <type_traits>
#include <variant>
#include <vector>
/*** Library code starts here ***/
// Library handler function definition to be registered. This cannot be changed.
// For simplicity I made the function arguments (int, int) to denote that this
// handler function does take some arguments passed later by the library.
// In reality these are simple, non-templated structs.
using LibraryHandler = std::function<void(int, int)>;
std::vector<LibraryHandler> g_libraryHandlers;
void RegisterLibraryHandler(LibraryHandler handler)
{
// Library code registering passed handler. This cannot be changed.
g_libraryHandlers.push_back(handler);
}
/*** End of library code ***/
/*** My "wrapper library" starts here ***/
// ReturnType is the type returned by the functions written by "wrapper library users".
// Types... is the list of all possible types held by 'ReturnType' that a given function is allowed to return.
template<typename T, typename... Types>
static inline constexpr bool isConstructible = (std::is_constructible_v<T, Types> || ...);
template<typename T, typename... Types>
static inline constexpr bool isAssignable = (std::is_assignable_v<T&, Types> || ...);
template<typename... Types>
class ReturnType
{
public:
template<typename T, std::enable_if_t<
isConstructible<T, Types...> &&
isAssignable<T, Types...>,
int> = 0>
static ReturnType Build(const T& data)
{
return ReturnType(data);
}
private:
template<typename T>
ReturnType(const T& data) : m_data(data) { }
std::variant<Types...> m_data;
};
template<typename T>
class ParamType
{
public:
ParamType() { }
const T& GetData() const { return m_data; }
private:
T m_data;
};
/*** This is where my problem is - how to write these functions to allow for
different logic (based on passed function signature) inside nested lambda? ***/
// Version registering functions taking no arguments
template<typename... Types>
void RegisterFunction(std::function<ReturnType<Types...>()> func)
{
auto wrapperLambda = [func](int a, int b) { // Construct lambda to conform with library interface ('LibraryHandler')
// Logic specific for 'func' with signature: ReturnType<Types...>() - step before call
func();
// Logic specific for 'func' with signature: ReturnType<Types...>() - step after call
};
RegisterLibraryHandler(wrapperLambda); // Register lambda inside library
}
// Version registering functions taking arguments through 'ParamType'
template<typename... Types, typename TParam>
void RegisterFunction(std::function<ReturnType<Types...>(const ParamType<TParam>)> func)
{
auto wrapperLambda = [func](int a, int b) { // Construct lambda to conform with library interface ('LibraryHandler')
// Logic specific for 'func' with signature: ReturnType<Types...>(const ParamType<TParam>) - step before call
func();
// Logic specific for 'func' with signature: ReturnType<Types...>(const ParamType<TParam>) - step after call
};
RegisterLibraryHandler(wrapperLambda); // Register lambda inside library
}
// Version registering functions taking library arguments directly
template<typename... Types, typename TParam>
void RegisterFunction(std::function<ReturnType<Types...>(int, int)> func)
{
auto wrapperLambda = [func](int a, int b) { // Construct lambda to conform with library interface ('LibraryHandler')
// Logic specific for 'func' with signature: ReturnType<Types...>(int, int) - step before call
func(a, b);
// Logic specific for 'func' with signature: ReturnType<Types...>(int, int) - step after call
};
RegisterLibraryHandler(wrapperLambda); // Register lambda inside library
}
/*** End of my "wrapper library" ***/
/*** This is how I'd like the "users of the wrapper library" to write the code ***/
struct SomeReturnData { char a; char b; };
struct OtherReturnData { char c; char d; };
struct SomeParameterType { int p; };
// Example 1 - function only ever returning a single type, taking no arguments
ReturnType<SomeReturnData> UserFunctionNoArgs()
{
SomeReturnData data{ 'x', 'y' };
return ReturnType<SomeReturnData>::Build(data);
}
// Example 2 - function taking parameter 'SomeParameterType' and returning 'SomeReturnData' or 'OtherReturnData'
// based on contents of passed argument.
ReturnType<SomeReturnData, OtherReturnData> UserFunctionArgs(const ParamType<SomeParameterType> param)
{
if (param.GetData().p == 1000)
return ReturnType<SomeReturnData, OtherReturnData>::Build(SomeReturnData());
return ReturnType<SomeReturnData, OtherReturnData>::Build(OtherReturnData());
}
// Example 3 - function requesting library arguments to be passed directly
ReturnType<SomeReturnData, OtherReturnData> UserHandlingLibraryDirectly(int libraryArg1, int libraryArg2)
{
if (libraryArg1 == libraryArg2)
return ReturnType<SomeReturnData, OtherReturnData>::Build(SomeReturnData());
return ReturnType<SomeReturnData, OtherReturnData>::Build(OtherReturnData());
}
int main()
{
// User registers written functions in the "wrapper library".
// This includes any 'regluar functions'...
RegisterFunction(UserFunctionNoArgs);
RegisterFunction(UserFunctionArgs);
RegisterFunction(UserHandlingLibraryDirectly);
// ... or lambdas with captures (all possible parameter combinations from examples above apply).
int someInt = 123;
auto userLambda = [someInt]() -> ReturnType<SomeReturnData, OtherReturnData> {
if(someInt < 100)
return ReturnType<SomeReturnData, OtherReturnData>::Build(SomeReturnData());
return ReturnType<SomeReturnData, OtherReturnData>::Build(OtherReturnData());
};
return 0;
}
My issue is with the RegisterFunction above - I'd basically want to write it the way it is above, which is obviously not possible (the compiler complains about not being able to deduce template parameters). My goal is to not change / cut down on possibilities / make any more complicated anything that's inside main.
Lambdas are not std::function, so cannot be deduced. Fortunately, std::function has CTAD (c++17) allowing to solve your issue with an extra overload:
template<typename Func>
void RegisterFunction(Func func)
{
RegisterFunction(std::function{func}); // forward to overload taking std::function
}
Demo

Template function signature unpacking in C++/CLI

Is there a way to apply the function-signature-as-template-parameter unpacking idiom in a way that works with C++/CLI managed types?
As an example, consider the following code:
#include <msclr/gcroot.h>
using namespace System;
template<typename... Args>
ref struct ManagedDelegate abstract
{
delegate void Fn(Args...);
};
template<typename Signature>
struct Method;
template<typename... Args>
struct Method<void(Args...)>
{
using Fn = typename ManagedDelegate<Args...>::Fn;
Method(Fn^ m) : m_Method(m) {}
void operator()(Args... args)
{
auto method = safe_cast<Fn^>(m_Method);
method(args...);
}
private:
msclr::gcroot<Fn^> m_Method;
};
void f1(int a, int b)
{
Console::WriteLine("a = {0}, b = {1}", a, b);
}
void f2(String^ s)
{
Console::WriteLine("s = {0}", s);
}
int main(array<String ^> ^args)
{
using Method1 = Method<void(int, int)>;
Method1 m1(gcnew Method1::Fn(&f1));
m1(4, 5);
using Method2 = Method<void(String^)>;
Method2 m2(gcnew Method2::Fn(&f2));
m2("hello world");
return 0;
}
(The separate ManagedDelegate is a little annoying, but it's not possible to declare a delegate type inside a native class, sadly.)
If you comment out all the Method2 code at the bottom, then this compiles and runs as you'd expect -- it calls f1(4, 5) and prints accordingly.
Trying to do the same thing with a managed type argument, however, causes the template to fail to match the specialisation and results in:
error C2027: use of undefined type 'Method<void (System::String ^)>'
Is this a compiler bug, or is there some way to get this to work? There are some constraints that I do need to keep to in order for this to work in my real code:
Method needs to be an unmanaged type that contains a gcroot of the delegate type.
The use of templates rather than generics is intended. I don't think any of this is possible with generics anyway.
The non-use of std::forward is also intended, since this also upsets managed types. (And I'm not intending to pass native reference arguments anyway, so it's unnecessary.)
While I prefer automatically creating the delegate type from the signature as shown here, it would also be acceptable to create the delegate outside and pass it in instead of a signature, eg:
delegate void Method1Delegate(int, int);
...
Method<Method1Delegate> m1(gcnew Method1Delegate(&f1));
But either way, I do need an Args... parameter list (both for the operator() and for other reasons). And I don't think it's possible to extract this from a managed delegate type.
I also want the operator() to keep using Args... from the Method type so that it won't accept the "wrong" parameters. (I did have an older version of the code that templated Args directly on operator(), but this gives IntelliSense the false impression that it would accept any parameters.)
If there is a way to do the above, then I'd probably want a version that works with a templated return type as well as just void. I know how to do that with the above code -- just that any rewrite shouldn't prevent that working if possible.
EDIT: as demonstration that the managed args sort of work in variadics, this can be added:
template<>
struct Method<void(String^)>
{
using Fn = typename ManagedDelegate<String^>::Fn;
Method(Fn^ m) : m_Method(m) {}
template<typename... Args>
void operator()(Args... args)
{
auto method = safe_cast<Fn^>(m_Method);
method(args...);
}
private:
msclr::gcroot<Fn^> m_Method;
};
This works, provided that the call is changed to m2(gcnew String("hello world")); to force the correct type, or operator() is changed to accept a single String^ parameter instead of an open variadic. So the problem is definitely in matching a variadic template specialisation, not elsewhere.
I can mostly do what I want by abandoning the function-signature-specialisation and just specifying the signature components separately:
template<typename R, typename... Args>
ref struct ManagedDelegate abstract
{
delegate R Fn(Args...);
};
template<typename R, typename... Args>
struct Method
{
using Fn = typename ManagedDelegate<R, Args...>::Fn;
Method(Fn^ m) : m_Method(m) {}
R operator()(Args... args)
{
auto method = safe_cast<Fn^>(m_Method);
return method(args...);
}
private:
msclr::gcroot<Fn^> m_Method;
};
//...
using Method2 = Method<void, String^>;
Method2 m2(gcnew Method2::Fn(&f2));
m2("hello world");
This is not ideal, but it does compile and work. I'm still interested in any alternative answer that does support unpacking a function signature type, however. (And I filed the original issue as a compiler bug.)

Template variadic function in template class won't compile

I'm trying to write a function for a template class which takes in a parameter that is a function pointer for a member class inside the private data of the big class. When you call that member, it calls that function on smaller class. (Confusing right?) To demonstrate, I have a non-working example here:
#include <vector>
#include <iostream>
using namespace std;
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A... args) { // pass in the function we want to call
return (mContainer.*func) (args...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
int main() {
MyClass<int, std::vector<int> > test;;
cout << test.call_me(&std::vector<int>::size) << endl; // works
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4); // doesn't work
return 0;
}
Please note that this isn't my actual code but a small example of what I'm trying to do. As you can see, I'm trying to call the size member function of the 'Private' (I have kept it public here for demonstration) vector class inside MyClass. This only works whenever I have no parameters for the compiler to unpack, but when I try to do the insert function (which has parameters to unpack), the compiler gives me an error of:
.\template.cpp: In function 'int main()':
.\template.cpp:24:71: error: no matching function for call to 'MyClass<int, std::vector<int> >::call_me(<unresolved overloaded function type>, std::vector<int>::iterator, int)'
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4);
^
.\template.cpp:10:10: note: candidate: template<class F, class ... A> auto MyClass<T, C>::call_me(F, A ...) [with F = F; A = {A ...}; T = int; C = std::vector<int>]
auto call_me(F func, A... args) { // pass in the function we want to call
^~~~~~~
.\template.cpp:10:10: note: template argument deduction/substitution failed:
.\template.cpp:24:71: note: couldn't deduce template parameter 'F'
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4);
This is the same error I'm getting in my actual production code, calling the variadic function with no parameters to unpack works, but if I give more than that, I get the same error message. This is my first real attempt to use Variadic templates, so any recommendation and help will be appreciated.
The problem here is that insert is an overloaded function. The compiler is not doing to try and resolve what overload you want in template argument deduction as there is no way for it to know. You have to cast the function to the type of the overload you want to use in order to give it a type. That would look like
using insert_func_t = std::vector<int>::iterator(std::vector<int>::*)(std::vector<int>::const_iterator, const int&);
test.call_me(static_cast<insert_func_t>(&std::vector<int>::insert), test.mContainer.begin(), 4);
In general it is
static_cast<return_type(class_name::*)(function_parameters)>(&class_name::function_name)
Another option would be to change the function a little and take a lambda that expresses what you want done. That would look like
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A... args) { // pass in the function we want to call
return func(mContainer, args...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
int main() {
MyClass<int, std::vector<int> > test;;
test.call_me([](auto& container, auto... args){ container.insert(args...); }, test.mContainer.begin(), 4);
return 0;
}
Basically you cannot take address of an unresolved overloaded function, because the compiler won't be able to choose the right function entry point address. During normal function call the compiler resolves overloaded function, but with templates like yours or std::bind() this won't work, because the parameters are used to call the template function, not the function you want to take address of.
You can manually resolve the overload like this:
using ftype = std::vector<int>::iterator(std::vector<int>::*)
(std::vector<int>::const_iterator, const std::vector<int>::value_type&);
test.call_me((ftype)(&std::vector<int>::insert), test.mContainer.begin(), 4); // works
It's easier to deal in function objects when doing this kind of thing. It offloads the problem of method overloads to the compiler.
Lambdas also work (they're function objects):
#include <vector>
#include <iostream>
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A&&... args) -> decltype(auto)
{ // pass in the function we want to call
return func(mContainer, std::forward<A>(args)...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
/*
* It's often easier to deal in function objects
*/
struct insert
{
template<class Container, class...Args>
decltype(auto) operator()(Container& cont, Args&&...args) const
{
return cont.insert(std::forward<Args>(args)...);
}
};
struct size
{
template<class Container, class...Args>
decltype(auto) operator()(Container& cont) const
{
return cont.size();
}
};
int main() {
MyClass<int, std::vector<int> > test;;
std::cout << test.call_me(size()) << std::endl; // works
test.call_me(insert(), test.mContainer.begin(), 4); // doesn't work
// or lambdas
auto insert2 = [](auto& container, auto&&...args) -> decltype(auto)
{
return container.insert(std::forward<decltype(args)>(args)...);
};
test.call_me(insert2, test.mContainer.begin(), 5);
return 0;
}

Using static_assert() to provide better compile-time errors (than the compilers)

Yesterday it took me ages to come to grips with a compile-time error caused by calling a const member function from a non-const object as in this example:
// my utility header
template<typename derived>
struct crtp_task : task
{
std::list<task*> list;
// note: cannot be const, as task::allocate_child() isn't
template<typename... Args>
void add_child(Args&&... args)
{
list.push_back(new(task::allocate_child())
derived(std::forward<Args>(args)...));
}
/* ... */
};
// an application
struct my_task : crtp_task<my_task>
{
some_data data;
/* ... */
my_task(some_data d) data(d) {}
void generate_children() const // constant member
{
/* ... */
some_data child_data = /* ... */;
this->add_child(child_data); // error: cannot call non-const member
}
};
The clang error message was several lines and too cryptic (not mentioning const), but gcc came up with a better error (though even more lines, but eventually complaining about me ignoring cv qualifiers).
So, to avoid this sort of thing in the future, I thought about using static_assert() in my utility header. My naive approach
// my utility header
template<typename derived>
struct crtp_task : task
{
std::list<task*> list;
// note: cannot be const, as task::allocate_child() isn't
template<typename... Args>
void add_child(Args&&... args)
{
list.push_back(new(task::allocate_child())
derived(std::forward<Args>(args)...));
}
// note: catch call from const objects
template<typename... Args>
void add_child(Args&&...) const
{
static_assert(false,"add_child() const called");
}
/* ... */
};
fails, as the compiler immediately triggers an error, even if the template void add_child() const is never called. How else can I make this work?
If you want some overload to cause a compilation error when it gets selected in overload resolution, you can use the new = delete feature.
template<typename... Args>
void add_child(Args&&...) const = delete;
This will generate a nice simple error along the lines of "use of deleted function void add_child(Args&&...) const".
static_assert must depend on a template parameter to be delayed after the instantiation of the template. Otherwise they will be "called" as soon as all information is available, in your case the false is ready pretty early in compilation.
To solve this, I usually make it "artificially" depend on a template parameter just like in:
template<class FOO>
void foo( const FOO& )
{
static_assert(sizeof(FOO)==0,"This function should never be instantiated");
}
Maybe in your case just deleting the function might be the better approach though.

templated operator() overload C++

someone already asked this question, but the thread ended up with the original question not getting answered.
suppose you have this:
template<size_t i, class f_type>
void call_with_i(f_type f);
functor_type is either:
a) a struct with a method that has the following signature:
template<size_t i> operator()() const;
or, b) a function that looks like this:
template<size_t i> foo();
I want "call_with_i<42>(foo)" to be equivalent to "foo<42>()", but I can't figure out the right syntax to make that happen. I'd be satified with a solution that does just (a) but (a)+(b) would be great. I've already tried these syntaxes:
f< i >(); // doesn't work
f()< i >; // doesn't work
f.operator< i >(); // doesn't work
f.operator()< i >; // doesn't work
f.operator()< i >(); // works on msvc, but doesn't work on gcc.
How do you invoke operator() with explicit template arguments? Is there a way to invoke it in a way that the same syntax would also call a templated free function?
p.s. If you're wondering what i'm using this for, its because I'm writing a function repeat_to where repeat_to<10>(f) invokes f(0) then f(1) ... f(10). I'm using this to iterate through multiple boost::fusion vectors in parallel by index. yeah, i could use iterators, or i could just use a named member function, but i still want to know the answer.
edit note: i striked out stuff because passing a templated free function as an arg doesn't make any sense.
The member template is a dependent name, because its semantics depend on the type of f_type. That means you should put "template" before its name (to disambiguate the use of the "less-than" token), similar to how you should put typename before dependent qualified names:
template<size_t i, class f_type>
void call_with_i(f_type f) {
f.template operator()<i>();
// f.template foo<i>();
}
As a workaround, you may use a helper type:
template<size_t N> struct size_t_ { }; // or boost::mpl::int_
template<size_t i, class f_type>
void call_with_i(f_type f) {
f(size_t_<i>());
}
Now, you could define your operator() as follows:
template<size_t i> void operator()(size_t_<i>) const {
// i was deduced automatically by the function argument.
}
This comes handy for templated constructors, for which you cannot do f_type()<i>() or something. They will have to be deducible in that case.
In a case like yours I would use boost::function as functor type. You can then pass both function objects and function pointers while retaining the same interface.
#include <iostream>
template<size_t i, class f_type> void call_with_i(f_type f);
struct A {
template < size_t i >
void operator()() const {
/* no link err in demo */
}
template < size_t i >
void foo() {
/* no link err in demo */
}
};
int main(int argc, char * const argv[]) {
A f;
enum { Constant = 42 };
f.operator()<Constant>();
f.foo<Constant>();
return 0;
}
Is there a way to invoke it in a way that the same syntax would also call a templated free function?
Can you clarify? (pseudocode, or something)