I would like to use a function as argument in a variadic template, why does the following not work? How do I make it work?
template<typename F, typename... Args>
F test(F f, const Args&&... args) {
return f(std::forward<Args>(args)...);
}
int simple(int i) {
return i;
}
int main()
{
std::cout << test(simple, 2); // error, 'std::forward': none of the 2 overloads could convert all the argument types
}
There are a couple of problems with your code.
First of all, you should use forwarding references, so you need to change const Args&&... to Args&&....
Then, test does not have to return F. So it is reasonable to use decltype(auto) here.
In addition to that, it makes sense to forward f too.
The fixed version might look like this:
template<typename F, typename... Args>
decltype(auto) test(F&& f, Args&&... args) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
WANDBOX EXAMPLE
The first problem is the return type. Your test function returns F which is a function pointer. Instead change it to auto to automatically deduce the return type.
The second issue is that std::forward requires a non-const reference.
You might use trailing return type:
template<typename F, typename... Args>
auto test(F f, Args&&... args) -> decltype(f(std::forward<Args>(args)...)) {
return f(std::forward<Args>(args)...);
}
But decltype(auto) (C++14 required) is a simpler solution:
template<typename F, typename... Args>
decltype(auto) test(F f, Args&&... args) {
return f(std::forward<Args>(args)...);
}
Related
Given the function type void(), void(int), and so on..., can we static_assert() that Args&&... args is compatible with the function type?
template <typename F = void(), typename... Args>
auto call(Args&&... args)
{
// TODO: check if F is compatible with Args
if constexpr (std::is_same_v<void, decltype(func(args...))>)
func(std::forward<Args>(args)...);
else
return func(std::forward<Args>(args)...);
}
Using decltype(func(args...)) will give an error, but it's not the best error. Also, is it possible that the static_assert() will make it worse by hiding the two types from the compiler output?
You have tagged C++17, so... what about using std::is_invocable?
I suppose something as follows
template <typename F = void(), typename... Args>
auto call (Args && ... args)
{
static_assert( std::is_invocable_v<F, Args...> );
// ...
}
I'd like to write a template function which can invoke a function with given parameters.
For instance, I can write a simple invoke function:
template<class F, class... Args>
inline auto invoke(F &&func, Args&&... args) -> decltype(auto)
{
return std::forward<F>(func)(std::forward<Args>(args)...);
}
This invoke accepts same count of parameter which f requires. However, I want to this template function allow additional unused parameters.
That is, I want to write some code like:
auto f = [] (auto a) {...};
invoke(f, 1, 2, 3);
Here, f accepts only one parameter so, I wish invoke ignore other parameters except the first one.
This can be accomplished very easily by get arity of the lambda unless the lambda is generic.
Since f here is generic lambda, as far as I know, there's no general way to figure out arity of f without explicit instantiation of its template operator()<...>.
How can I wirte my invoke?
One possibility:
#include <utility>
#include <cstddef>
#include <tuple>
template <std::size_t... Is, typename F, typename Tuple>
auto invoke_impl(int, std::index_sequence<Is...>, F&& func, Tuple&& args)
-> decltype(std::forward<F>(func)(std::get<Is>(std::forward<Tuple>(args))...))
{
return std::forward<F>(func)(std::get<Is>(std::forward<Tuple>(args))...);
}
template <std::size_t... Is, typename F, typename Tuple>
decltype(auto) invoke_impl(char, std::index_sequence<Is...>, F&& func, Tuple&& args)
{
return invoke_impl(0
, std::index_sequence<Is..., sizeof...(Is)>{}
, std::forward<F>(func)
, std::forward<Tuple>(args));
}
template <typename F, typename... Args>
decltype(auto) invoke(F&& func, Args&&... args)
{
return invoke_impl(0
, std::index_sequence<>{}
, std::forward<F>(func)
, std::forward_as_tuple(std::forward<Args>(args)...));
}
DEMO
Here's a code I've written for my needs based on Piotr's answer:
template <std::size_t... Is, typename F, typename Tuple>
void invoke_impl(
std::index_sequence<Is...>, F&& f, Tuple&& args,
std::enable_if_t<std::is_invocable_v<F, std::tuple_element_t<Is, Tuple>...>,
void>* = nullptr)
{
std::invoke(std::forward<F>(f), std::get<Is>(args)...);
}
template <std::size_t... Is, typename F, typename Tuple>
void invoke_impl(
std::index_sequence<Is...>, F&& f, Tuple&& args,
std::enable_if_t<
!std::is_invocable_v<F, std::tuple_element_t<Is, Tuple>...>, void>* =
nullptr)
{
static_assert(sizeof...(Is) > 0, "Not invocable with arguments supplied");
if constexpr (sizeof...(Is) > 0)
{
invoke_impl(std::make_index_sequence<sizeof...(Is) - 1>(),
std::forward<F>(f), std::move(args));
}
}
// invokes function with possibly too many parameters provided
template <typename F, typename... Args>
void invoke(F&& f, Args&&... args)
{
invoke_impl(std::make_index_sequence<sizeof...(Args)>(), std::forward<F>(f),
std::forward_as_tuple(std::forward<Args>(args)...));
}
It is a little bit improved:
it leverages std::invoke so it works with more use cases, like pionter to members
it matches parameters count starting from sizeof...(Args) so chooses better matched operator() overload
Here's a demo:
struct test
{
void foo()
{
std::cout << "foo" << std::endl;
}
void operator()()
{
std::cout << "operator()()" << std::endl;
}
void operator()(float)
{
std::cout << "operator()(float)" << std::endl;
}
};
int main()
{
test obj;
invoke(&test::foo, &obj, 1, 2, 3); // foo
invoke(obj); // operator()()
invoke(obj, 1, 2, 3); // operator()(float)
// invoke(5); // assert failed
}
Here's a live demo
namespace detail {
template <class F, class... Args>
inline auto INVOKE(F&& f, Args&&... args) ->
decltype(std::forward<F>(f)(std::forward<Args>(args)...)) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
template <class Base, class T, class Derived>
inline auto INVOKE(T Base::*pmd, Derived&& ref) ->
decltype(std::forward<Derived>(ref).*pmd) {
return std::forward<Derived>(ref).*pmd;
}
template <class PMD, class Pointer>
inline auto INVOKE(PMD pmd, Pointer&& ptr) ->
decltype((*std::forward<Pointer>(ptr)).*pmd) {
return (*std::forward<Pointer>(ptr)).*pmd;
}
template <class Base, class T, class Derived, class... Args>
inline auto INVOKE(T Base::*pmf, Derived&& ref, Args&&... args) ->
decltype((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...)) {
return (std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...);
}
template <class PMF, class Pointer, class... Args>
inline auto INVOKE(PMF pmf, Pointer&& ptr, Args&&... args) ->
decltype(((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...)) {
return ((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...);
}
} // namespace detail
template< class F, class... ArgTypes>
decltype(auto) invoke(F&& f, ArgTypes&&... args) {
return detail::INVOKE(std::forward<F>(f), std::forward<ArgTypes>(args)...);
}
I saw the implementation above from here:
http://en.cppreference.com/w/cpp/utility/functional/invoke
Then I wonder how the compilers match the exact version required. Does SFINAE work on trailing return type?
does SFINAE work on tailing return type?
Yes. The trailing return type syntax doesn't enable any new functionality, it merely makes it easier to write some cases of return types that depend on parameter types.
template <class F, class... Args>
inline auto INVOKE(F&& f, Args&&... args) ->
decltype(std::forward<F>(f)(std::forward<Args>(args)...) { ... }
could have equivalently been written as
template <class F, class... Args>
inline decltype(std::forward<F>(std::declval<F&>())(std::forward<Args>(std::declval<Args&>())...))
INVOKE(F&& f, Args&&... args) { ... }
for instance, and the same for all the others. That could be simplified, but even if you simplify it, the fact that the return type cannot use the same syntax as the return expression makes it hard to follow what's going on. Hence the new syntax.
The only time SFINAE doesn't work is for deduced return types. They also use auto, but it's not the auto keyword by itself that disables SFINAE.
I'm trying to write my own apply function using variate template. Here is the code I have:
template<typename...>
struct types{
};
template<typename T, typename... Args>
struct Func{
template<typename F, typanem... Types>
T call(F f, std::tuple<Types...>& params, Args... args){
return _call(f, params, types<Types...>{}, args...);
}
template<typename F, typename Tuple, typename Head, typename... Tail, typename... Args>
T _call(F f, Tuple& t, types<Head, Tail...>, Args&&... args){
_call(f, t, types<Tail...>{}, std::forward<Args>(args)..., std::get<sizeof...(Arg)>(t).DrawSample()));
}
T _call(F f, Tuple& t, types<>, Args... vs){
return f(vs...)
}
};
I can compile and run the above code without any difficulty. Now I want to make the function call(...) being invoked lazily. In other words, I can first construct the function by passing in all parameters needed for the computation:
int getMax(float f1, float f2, float f3){
if(f1 >= f2 && f1 >= f3){
return 1;
}
if(f2 >= f1 && f2 >= f3){
return 2;
}
if(f3 >= f1 && f3 >= f2){
return 3;
}
}
Func<int> func;
//Gaussian(mu, sd) is an object which can generate random values based on Gaussian
//distribution described with mu(mean) and sd(standard deviation).
Gaussian *g1 = Gaussian(0.3, 0.2);
Gaussian *g2 = Gaussian(0.2, 0.3);
Gaussian *g3 = Gaussian(0.3, 0.3);
func.setCall(getMax, std::make_tuple(*g1, *g2, *g3);
cout<<func.DrawSample();
After constructing the function, I hope to get the result of the getMax() function lazily each time I make a query for func.DrawSample(). Under the hood, perhaps DrawSample() calls call(...). However, is there anyway for me to change the code above in order to create a setCall(...) whose purpose is to store everything needed for later function calls?
Please let me know if my question is still unclear. Thanks a lot for your help!
Try this:
template<class Func, class... Args>
int applyDrawSample(Func func, Args... args)
{
return func(args.DrawSample()...);
}
template<class Func, class... Args>
auto bind_helper(Func func, Args... args)
-> decltype(bind(applyDrawSample<Func, Args...>, func, args...))
{
return bind(applyDrawSample<Func, Args...>, func, args...);
}
Usage:
auto func = bind_helper(getMax, Gaussian(...), Gaussian(...), Gaussian(...));
func();
A trivial extra lambda can change the last call to look like func->DrawSample(), if you really want it, and is left as an exercise.
EDIT
If you need a type for func above, it can be std::function:
function<int()> func = bind_helper(...);
The function signature (in this case, a function with no arguments, returning an int) for std::function needs to be compatible with what you are assigning.
Use std::function<int()> and lambdas.
std::function<int()> func;
func = [=]()->int {
return getMax( Guassian(0.3,0.2), Guassian(0.2,0.3), Guassian(0.3,0.3) );
};
std::cout << func();
If you really, really need your interface, simply store a std::function<T()> within your class, and the setCall simply assigns to it.
But really, your object is some anonymous type that can be invoked to produce an int -- std::function solves the problem. You'll have to engage in type erasure anyhow, as the type of your class does not include the function signature, so you probably won't be any more efficient.
With the suggestion provided by DanielKO, I finally come up with a solution for my specific scenario.
Here is the final version of my compiled code.
template<class Func, class... Args>
int applyDrawSample(Func func, Args&&... args){
return func((*args).DrawSample()...);
}
template<class Func, class... Args>
auto bind_helper(Func func, Args&&... args) ->decltype(bind(applyDrawSample<Func, Args...>,
func, args...))
{
return bind(applyDrawSample<Func, Args...>, func, args...);
}
template<typename T>
struct UncertainFunc{
template<typename F, typename... Args>
void setFunc(F f, Args... args){
function = bind_helper(f, args...);
}
T DrawSample(){
return function();
}
std::function<T()> function;
};
UncertainFunc<int> ufunc;
ufunc.setFunc(getMax, &(Gaussian(0.3, 0.2), &Gaussian(0.2, 0.3), &Gaussian(0.2, 0.2));
ufunc.DrawSample();
Especially, it seems that I cannot put the bind_helper(...) function into my class definition for some reason (perhaps auto type?).
Consider the following function in C++11:
template<class Function, class... Args, typename ReturnType = /*SOMETHING*/>
inline ReturnType apply(Function&& f, const Args&... args);
I want ReturnType to be equal to the result type of f(args...)
What do I have to write instead of /*SOMETHING*/ ?
I think you should rewrite your function template using trailing-return-type as:
template<class Function, class... Args>
inline auto apply(Function&& f, const Args&... args) -> decltype(f(args...))
{
typedef decltype(f(args...)) ReturnType;
//your code; you can use the above typedef.
}
Note that if you pass args as Args&&... instead of const Args&..., then it is better to use std::forward in f as:
decltype(f(std::forward<Args>(args)...))
When you use const Args&..., then std::forward doesn't make much sense (at least to me).
It is better to pass args as Args&&... called universal-reference and use std::forward with it.
It doesn't need to be a template parameter, since it isn't used for overload resolution. Try
template<class Function, class... Args>
inline auto apply(Function&& f, const Args&... args) -> decltype(f(std::forward<const Args &>(args)...));
There are situations where std::result_of is more useful. For example, say you want to pass this function:
int ff(int& out, int in);
and inside apply() call it like so
int res;
f(res, args...);
then I wouldn't know how to use decltype, because I have no int lvalue reference at hand. With result_of, you don't need variables:
template<class Function, class... Args>
typename std::result_of<Function(const Args&...)>::type apply(Function&& f, const Args&... args)
{
typedef typename std::result_of<F(const Args&...)>::type ReturnType;
// your code
}