I want to use std::bind with template function. Is it somehow possible?
P.S. It is IMPORTANT to use std::bind, because I know at least one solution through lambdas and want to find out if there is std::bind solution.
#include <iostream>
#include <functional>
#include <memory>
using namespace std;
struct foo : std::enable_shared_from_this<foo>
{
void f()
{
// doesn't compile, error : no matching function for call to 'bind'
auto cb = std::bind(&foo::handle, shared_from_this(), placeholders::_1, placeholders::_2);
}
template <typename T, typename U>
void handle(T, U)
{
}
};
int main()
{
return 0;
}
handle is not a template function. There are no "template functions". handle is a function template, ie it is a template, it is not a function. You cannot std::bind to a template. You can only std::bind to a callable.
The trick is to defer instantiation of the template and deduction of the template parameters to when the function is actually called:
#include <iostream>
#include <functional>
#include <memory>
using namespace std;
struct foo {
struct handle_caller {
template <typename T,typename U>
void operator()(foo* f, T t,U u){
f->handle(t,u);
}
};
void f()
{
auto cb = std::bind(handle_caller{},this, placeholders::_1, placeholders::_2);
}
template <typename T, typename U>
void handle(T, U)
{
}
};
int main()
{
return 0;
}
The callable passed to bind is an object of a concrete type handle_caller. It is not a template. Only when cb is called the parameters are forwarded to handle_caller::operator() where the template arguments can be deduced.
Lambdas can do this out-of-the box, because a lambda with auto arguments is of a concrete type and only its operator() is a template:
#include <iostream>
#include <functional>
#include <memory>
using namespace std;
struct foo {
void f()
{
auto cb = std::bind([](auto f,auto t,auto u){ f->handle(t,u);},this, placeholders::_1, placeholders::_2);
}
template <typename T, typename U>
void handle(T, U)
{
}
};
int main()
{
return 0;
}
However, once you use the lambda there is no need for std::bind anymore, because you can bind the parameters via a lambda capture. std::bind is the ancient way to bind parameters, it is convoluted and has clunky syntax. I have read of cases that can be done with std::bind but not with a lambda, but I have never encountered one.
PS: Note that I removed the shared_from_this stuff from your code, because I know it can be used wrong easily, but I am not sure how to use it correctly. As cb is only local to foo::f there is no need to worry about the lifetime of this in the example code.
&foo::handle is not valid C++, because foo::handle is not a function. foo::handle<int, int> is a function, and foo::handle<double, std::string> is a different function.
You will have to wrap it in something, so you may as well use a lambda.
Related
I see a few similar questions, but they don't seem to get at this.
I can overload a function on a template:
template <typename T> void foo(); // Called as e.g., foo<int>();
template <std::size_t I> void foo(); // Called as e.g., foo<2>();
Is there a way to do something similar with a class, where I can have either MyClass<int> or MyClass<2>?
I can't see a way to do it. (My real goal is to have a static constexpr instance of an invokable that acts like std::get. Whereas std::get is templated on its "indexing" parameter and on the argument type, I'd like to make one that is invokable on its own, so myns::get<2> and myns::get<int> are both invokable and when invoked act like std::get<2>(tup) and std::get<int>(tup) respectively.
Naively you'd hope something like this would work, but the auto is a type:
template <auto IndOrType>
constexpr auto get = [](auto&& tup) {
return std::get<IndOrType>(std::forward<decltype(tup)>(tup));
};
I can make a getter function that returns a lambda, but then it's called with () as in myns::get<2>()(tup) or myns::get<int>()(tup).
You could specialize the class using the helper type std::integral_constant<int,N>. Though unfortunately this doesn't exactly allow the MyClass<2> syntax:
#include <type_traits>
template<typename T>
class MyClass
{
};
template<int N>
using ic = std::integral_constant<int,N>;
template<int N>
class MyClass<ic<N>>
{
};
int main()
{
MyClass<int> a;
MyClass<ic<2>> b;
}
https://godbolt.org/z/84xoE1Yd4
We implement a system that passes callbacks to object-instance member-functions. This works nicely, see the code below. The problem is that the current state of the implementation handles only non-const member functions.
The code below compiles and demonstrates that the system is working. As soon as the /* const */ is included, it no longer compiles.
The error messages are localized not English, but the first message is 'incomplete type'.
Logically, a call to a const member-function should be not more constrained than a call to a non-const member-function, so it seems that the basic goal is sensible.
It is clear that the type of a const-member differs from that of a non-const member. The problem is that we do not find a way to express to the compiler that the code is also valid for const members.
Where and how in the shown WrapP can we express that a const is acceptable? Is it possible to define a single template that accepts both, const and non-const, member functions?
#include <algorithm>
#include <functional>
#include <iostream>
using std::cout;
using std::endl;
template <auto F>
struct WrapP;
template <typename T, typename R, typename ... Args, R(T::* F)(Args...)>
struct WrapP<F> {
T* obj_;
WrapP(T* instance) : obj_(instance) {}
auto operator()(Args... args) const {
return (obj_->*F)(args...);
}
};
struct foo {
// Const below is needed, but could not be activated.
auto bar(double) /* const */ -> int {
return 314; };
};
int main() {
foo x;
// Create a functor for foo::bar
WrapP<&foo::bar> fp{ &x };
// Call the functor.
std::cout << fp( 3.14159265 ) << std::endl;
return 0;
}
If you want to specialize WrapP for a const member function, you need to specify that:
template <typename T, typename R, typename ... Args, R(T::* F)(Args...) const>
struct WrapP<F> { // ^___^
// ...
};
As far as I'm aware, there isn't a way to allow for either const or non-const member function pointers in a template parameter list, so you'll have to write separate specializations for those cases.
Do not specialize WrapP -- instead keep taking auto F as your template parameter, and then extract the information you need using something like Boost.CallableTraits or your own homegrown solution:
template <auto F>
struct WrapP {
using T = boost::callable_traits::class_of_t<decltype(F)>;
using R = boost::callable_traits::return_type_t<decltype(F)>;
T* obj_;
WrapP(T* instance) : obj_(instance) {}
template <typename... Args>
auto operator()(Args... args) const {
return (obj_->*F)(args...);
}
};
It is also possible to extract Args... but it's a bit more cumbersome as you get a std::tuple back.
i simplified the problem as much as i could so here is the function in question:
class Test
{
public:
template<class T>
void ExecuteFunction(std::function<void(T)> f)
{
}
};
if i call the function with int-typing everything works fine, however, if i call it with a void-typed lambda it doesn't compile anymore.
Test test;
test.ExecuteFunction<void>( // doesn't compile
[](void)->void
{
int i = 5;
});
test.ExecuteFunction<int>( // this compiles
[](int)->void
{
int i = 5;
});
Compiler errors:
Error C2672 'Test::ExecuteFunction': no matching overloaded function found
Error C2770 invalid explicit template argument(s) for 'void Test::ExecuteFunction(std::function<void(P)>)'
Error (active) no instance of function template "Test::ExecuteFunction" matches the argument list
is there a way around this? how would someone specify the template so that both calls work?
Sure, void in parentheses is but a vintage C-style sugar. You'll have to specialize your template:
template<> void Test::ExecuteFunction<void>(std::function<void()> f) {}
If that does not compile, well, you can use a helper template to encapsulate the type-selection:
#include <iostream>
#include <functional>
template<class T> struct callable {
using type = std::function<void(T)>;
};
template<class T> using callable_t =
typename callable<T>::type;
template<> struct callable<void> {
using type = std::function<void()>;
};
class Test
{
public:
template<class T>
void ExecuteFunction(callable_t<T> f) {}
};
int main() {
Test test;
test.ExecuteFunction<void>( // does compile
[](void)->void {});
test.ExecuteFunction<int>( // this compiles
[](int)->void {});
}
But be aware that this way you'll have to also do something to the arguments passing (in your example, a generic case's argument is unary yet specialization for void expects a nullary function object).
You can add an overload to the class like this:
// as before:
template<class T>
void ExecuteFunction(std::function<void(T)> f) {}
// new overload (not a template):
void ExecuteFunction(std::function<void()> f) {}
As you can't use type deduction anyhow, you can now explicitly call this function by not specifying any template parameter as follows.
Test test;
test.ExecuteFunction(
[](void)->void
{
int i = 5;
});
Is too late to play?
I propose another solution based on a custom type trait (with a specialization for void) that, given a T type, define the correct std::function type; i mean
template <typename T>
struct getFuncType
{ using type = std::function<void(T)>; };
template <>
struct getFuncType<void>
{ using type = std::function<void()>; };
This way your ExecuteFunction() simply become
template <typename T>
void ExecuteFunction (typename getFuncType<T>::type f)
{
}
If you want simplify a little the use of getFuncType, you can add a using helper to extract the type
template <typename T>
using getFuncType_t = typename getFuncType<T>::type;
so the ExecuteFunction() can be simplified as follows
template <typename T>
void ExecuteFunction (getFuncType_t<T> f)
{
}
Is there a standard way to get the types of a function's arguments and pass around these types as a template parameter pack? I know that this is possible in C++ because it has been done before.
I was hoping that with C++14 or the upcoming C++1z, there would be an idiomatic way to implement arg_types<F>... here:
template <typename ...Params>
void some_function(); // Params = const char* and const char*
FILE* fopen(const char* restrict filename, const char* restrict mode);
int main(){
some_function<arg_types<fopen>...>();
}
Just to be clear, an answer claiming that there is no standard way to do this is not an answer. If there is no answer, I would prefer that the question remain unanswered until the solution is added to C++500 or until the heat death of the universe, whichever happens earlier :)
Edit: A deleted answer noted that I can use PRETTY_FUNCTION to get the names of parameter types. However, I want the actual types. Not the names of those types.
This syntax is slightly different.
First, because types are easier to work with than packs, a type that holds a pack. The using type=types; just saves me work in the code that generates a types:
template<class...>struct types{using type=types;};
Here is the workhorse. It takes a signature, and produces a types<?...> bundle containing the arguments for the signature. 3 steps so we can get nice clean C++14esque syntax:
template<class Sig> struct args;
template<class R, class...Args>
struct args<R(Args...)>:types<Args...>{};
template<class Sig> using args_t=typename args<Sig>::type;
Here is a syntax difference. Instead of directly taking Params..., we take a types<Params...>. This is similar to the "tag dispatching" pattern, where we exploit template function type deduction to move arguments into the type list:
template <class...Params>
void some_function(types<Params...>) {
}
My fopen is different, because I don't want to bother #includeing stuff:
void* fopen(const char* filename, const char* mode);
And the syntax is not based off of fopen, but rather the type of fopen. If you have a pointer, you'd need to do decltype(*func_ptr) or somesuch. Or we could augment the top to handle R(*)(Args...) for ease of use:
template<class Sig>
struct args<Sig*>:args<Sig>{}; // R(*)(Args...) case
template<class Sig>
struct args<Sig&>:args<Sig>{}; // R(&)(Args...) case
then test code:
int main(){
some_function(args_t<decltype(fopen)>{});
}
live example.
Note that this does not work with overloaded functions, nor does it work with function objects.
In general, this kind of thing is a bad idea, because usually you know how you are interacting with an object.
The above would only be useful if you wanted to take a function (or function pointer) and pop some arguments off some stack somewhere and call it based off the parameters it expected, or something similar.
Inspired by #Yakk, here is a slightly simplified version:
First we define helper meta function to store function argment types as tuple.
template<typename Sig>
struct signature;
template<typename R, typename ...Args>
struct signature<R(Args...)>
{
using type = std::tuple<Args...>;
};
We use concept to restrict input as function
template<typename F>
concept is_fun = std::is_function_v<F>;
Here is our function "arguments" to retrieve input's argument types. Depends on input parameter, we overload "arguments" function to accept both reference and non reference.(free function is always passed by reference. We don't even have to have function body, only return type is enough as this is meta function.
template<is_fun F>
auto arguments(const F &) -> typename signature<F>::type;
Here is testing:
void foo(const string &, int, double)
{}
static_assert(std::is_same_v<decltype (arguments(foo)),
std::tuple<const string &, int, double>>);
My full-fledged version is here which also supports lambda, functor, member function pointer
Use Boost.FunctionTypes and std::index_sequence. Below is an example which prints the argument types of the function func. You can change the doit static function to do what you want. See it in action here.
template <typename FuncType>
using Arity = boost::function_types::function_arity<FuncType>;
template <typename FuncType>
using ResultType = typename boost::function_types::result_type<FuncType>::type;
template <typename FuncType, size_t ArgIndex>
using ArgType = typename boost::mpl::at_c<boost::function_types::parameter_types<FuncType>, ArgIndex>::type;
void func(int, char, double) {}
template <typename Func, typename IndexSeq>
struct ArgPrintHelper;
template <typename Func, size_t... Inds>
struct ArgPrintHelper<Func, integer_sequence<size_t, Inds...> >
{
static void doit()
{
string typeNames[] = {typeid(ResultType<Arg>).name(), typeid(ArgType<Func, Inds>).name()...};
for (auto const& name : typeNames)
cout << name << " ";
cout << endl;
}
};
template <typename Func>
void ArgPrinter(Func f)
{
ArgPrintHelper<Func, make_index_sequence<Arity<Func>::value> >::doit();
}
int main()
{
ArgPrinter(func);
return 0;
}
Headers(moved down here to reduce noise in the above code snippet):
#include <boost/function_types/function_type.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/function_arity.hpp>
#include <algorithm>
#include <iostream>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <tuple>
#include <utility>
using namespace std;
For boost users, #include <boost/type_traits.hpp>
boost::function_traits<decltype(function)>::arg1_type
boost::function_traits<decltype(function)>::arg2_type
// boost::function_traits<decltype(function)>::argN_type
using FopenArg1 = boost::function_traits<decltype(fopen)>::arg1_type;
using FopenArg2 = boost::function_traits<decltype(fopen)>::arg2_type;
void some_function(FopenArg1, FopenArg2);
Boost Document
With a C++17 (or later) conforming compiler, you can use this:
#include<iostream>
template<typename type, typename...args>
void getFuncInfo(type(*func)(args...))
{
// some code here...
// here my example:
((std::cout << typeid(args).name() << "\n"),...);
}
// every Augments you can imagines...
void someRandomFunction(int a, float b, double c, const char* d, int e[], std::pair<int, const char*> f)
{
}
// test out in main.
int main()
{
getFuncInfo(someRandomFunction);
std::cin.get();
}
The following TestClass works:
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
void ext_fun(const float f, int i)
{
std::cout << f << '\t' << i << std::endl;
}
template <typename T>
class TestClass
{
public:
boost::function <void (const T)> test_fun;
};
int main()
{
TestClass<float> tt;
tt.test_fun = std::bind(ext_fun, std::placeholders::_1, 10);
tt.test_fun(2.1);
return(0);
}
However, I would prefer to define test_fun as a member function template, i.e., something like
class TestClass
{
public:
template <typename T> boost::function <void (const T)> test_fun;
};
But if I do it, I get this compiler error: "error: data member ‘test_fun’ cannot be a member template"
Is it possible to define a member function template using a boost::function? If yes, how?
Thank you
--Matteo
Is it possible to define a member function template using a boost::function? If yes, how?
I think you have a little bit of confusion going on here. A function template is, first of all, a function. Your test_fun is not a function, it's a member object of the class TestClass. Member objects can't be templatized in C++.