how to emulate fold expression in variadic function? - c++

Its seems that Microsoft is slow to support Fold Expressions and I'm struggling to find a way to emulate it. I have the following cutdown example. This fails to compile on Visual Studio 2017 because of no support for Fold Expressions.
Any idea how to emulate it please?
template<typename... Args>
void get(weak_ptr<sqlite::database> awdb_, Args&&... args) {
(*awdb_.lock() << ... << args);
}

Before fold expressions, there was the expander trick:
template <class... Args>
void get(weak_ptr<sqlite::database> awdb_, Args&&... args) {
if (auto db = awdb_.lock()) {
using expander = int[];
(void)expander{0,
(void(*db << std::forward<Args>(args)), 0)...
};
}
}
As T.C. points out, this isn't necessarily strictly equivalent if << does something other than returning *this back, so we could write:
template <class F, class Arg>
decltype(auto) fold(F&& , Arg&& arg) {
return std::forward<Arg>(arg);
}
template <class F, class A0, class A1, class... Args>
decltype(auto) fold(F&& f, A0&& a0, A1&& a1, Args&&... args) {
return fold(f, f(a0, a1), std::forward<Args>(args)...);
}
template <class... Args>
void get(weak_ptr<sqlite::database> awdb_, Args&&... args) {
if (auto db = awdb_.lock()) {
auto lshift = [](auto&& a, auto&& b) -> decltype(auto) { return a << std::forward<decltype(b)>(b); };
fold(lshift, *db, std::forward<Args>(args)...);
}
}

Related

How to pass a Callable object in c++17 to be used with std::invoke

Why the following does not compile when passing i to the constructor. The other similar constructs compile.
#include <iostream>
#include <functional>
int RetXPrintU(int x, uint u)
{
std::cout << "RetXprintU(): " << u << std::endl;
return x;
}
template <typename Fn, typename... Args>
void Call(Fn&& fun, Args&&... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
template <typename Fn, typename... Args>
class CallableObj
{
public:
explicit CallableObj(Fn&& fun, Args&&... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
};
int main() {
int i = 4;
std::invoke(RetXPrintU, i, 8u);
Call(RetXPrintU, i, 8u);
CallableObj co(RetXPrintU, i, 8u); // WHY I DO NOT COMPILE?
//CallableObj co(RetXPrintU, 0, 8u); // WHY I COMPILE?
return 0;
}
The issue here is you need to move the template from the class to the constructor. When you have
template <typename Fn, typename... Args>
class CallableObj
{
public:
explicit CallableObj(Fn&& fun, Args&&... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
};
Args&&... is not a variadic forwarding reference because it is deduced for the class itself and when you call CallableObj co(RetXPrintU, i, 8u); the class is instantiated and the constructor gets stamped out as
explicit CallableObj(int(int, unsigned int)&& fun, int&& arg1, unsigned int&& arg2)
What we want is
class CallableObj
{
public:
template <typename Fn, typename... Args>
explicit CallableObj(Fn&& fun, Args&&... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
};
so that now Args will be deduced when the constructor is called and Args&& is now a forwarding reference.
The reason CallableObj co(RetXPrintU, 0, 8u); worked in your example is because 0 is a prvalue and a prvalue can bind to an rvalue reference.
As the error message says, the compiler can't deduce the template parameters for CallableObj. You need add a deduction guide for that:
template <typename Fn, typename... Args>
CallableObj(Fn&& fun, Args&&... args) -> CallableObj<Fn, Args>...>;
The whole code reads:
template <typename Fn, typename... Args>
class CallableObj
{
public:
explicit CallableObj(Fn fun, Args... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
};
template <typename Fn, typename... Args>
CallableObj(Fn&& fun, Args&&... args) -> CallableObj<Fn, Args...>;
As #Jarod42 pointed out there's no need to make the constructor a template itself (as it was in the first version of the answer).
And here is a live example (corrected version by #Jarod42).
I was assuming your code is just a minimal example and you need the class to be a template. If that is not the case you better go with the other solution.

Variadic template, function as argument

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)...);
}

Invoke a function/functor with parameters more than arguments

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

How to resolve constructor signature in factory function

I want to support one of two possible signatures of the constructor of the class T when creating its instance in the create(...) function below:
template <class Т, typename... Args>
T* create(Special* s, Args&&... args) {
T* t =
// If such a constructor exists, this:
new T(s, std::forward<Args>(args)...);
// Otherwise, this:
new T(std::forward<Args>(args)...);
}
I tried a few monstrous template constructions that did not cut it. The solution for resolving a member function involves SFINAE-failing a decltype of a member function, but this is not apparently possible with a constructor, as it does not have a signature type of its own.
Is this even possible in C++11, and is there any library support?
Just use std::is_constructible:
namespace detail
{
template<typename T, typename... Ts>
auto create(std::true_type, Special* s, Ts&&... args) {
return new T(s, std::forward<Ts>(args)...);
}
template<typename T, typename... Ts>
auto create(std::false_type, Special*, Ts&&... args) {
return new T(std::forward<Ts>(args)...);
}
}
template<class T, typename... Args>
T* create(Special* s, Args&&... args) {
using tag = is_constructible<T, Special*, Args...>;
return detail::create<T>(tag{}, s, std::forward<Args>(args)...);
}
live demo
template <class Т, typename... Args>
T* create_impl(std::true_type, Special* s, Args&&... args) {
return new T(s, std::forward<Args>(args)...);
}
template <class Т, typename... Args>
T* create_impl(std::false_type, Special*, Args&&... args) {
return new T(std::forward<Args>(args)...);
}
template <class Т, typename... Args>
T* create(Special* s, Args&&... args) {
T* t = create_impl<T>(std::is_constructible<T, Special*&, Args&&...>{},
s, std::forward<Args>(args)...);
// ...
return t;
}

How does std::invoke(C++1z) work?

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.