How to Combine Std::Bind(), Variadic Templates, and Perfect Forwarding

How to combine std::bind(), variadic templates, and perfect forwarding?

Binding to &foo::invoke_impl<Args...> will create a bound function that takes an Args&& parameter, meaning an rvalue. The problem is that the parameter passed will be an lvalue because the argument is stored as a member function of some internal class.

To fix, utilize reference collapsing rules by changing &foo::invoke_impl<Args...> to &foo::invoke_impl<Args&...> so the member function will take an lvalue.

auto bound = std::bind(&foo::invoke_impl<Args&...>, this,
std::placeholders::_1, std::forward<Args>(args)...);

Here is a demo.

c++ how to combine std::bind and variadic tuples?

Don't use bind, use a lambda instead:

auto f = [&t](auto... args){ t.iterate(args...); };
std::apply(f, args);

If you want perfect forwarding, that would look like:

auto f = [&t](auto&&... args){ t.iterate(std::forward<decltype(args)>(args)...); };
std::apply(f, args);

std::bind with variadic template member function and universal references

If you specify the template argument as int explicitly, then the parameter type of func_to_bind would become int&&, i.e. an rvalue-reference type. Note that the stored arguments are passed to the invokable object as lvalues by std::bind:

Otherwise, the ordinary stored argument arg is passed to the invokable object as lvalue argument:

The lvalue can't be bound to the rvalue-referece parameter then invocation fails.

If you specify the template argument as int& explicitly, then the parameter type of func_to_bind becomes int&, i.e. an lvalue-reference type; lvalue could be bound to lvalue-reference then it works fine.

And if you change the parameter type of func_to_bind to ARGS&, it'll be always an lvalue-reference, for the same reason above it'll work fine.

How would one call std::forward on all arguments in a variadic function?

You would do:

template <typename ...Params>
void f(Params&&... params)
{
y(std::forward<Params>(params)...);
}

The ... pretty much says "take what's on the left, and for each template parameter, unpack it accordingly."

Variadic template templates and perfect forwarding

That's exactly right. I would expect it to work. So I think that GCC is in error with rejecting that. FWIW:

#include <utility>

template <template <typename...> class TemplateClass, typename... Args>
TemplateClass<Args...> make(Args&&... args)
{
return TemplateClass<Args...>(std::forward<Args>(args)...);
}

int main() {
make<std::pair>(1, 2);
}

// [js@HOST2 cpp]$ clang++ -std=c++0x main1.cpp
// [js@HOST2 cpp]$

Variadic templates and perfect forwarding to specific template class

template <class T, class D>
myArgs(myClassBase<T, D>&& rhs) :
m_data(std::forward< myClassBase<T, D> >(rhs))
{
}

rhs there is an rvalue reference, not a forwarding reference. A forwarding reference in a function parameter be of the form T&& where T is some deduced template parameter. You can fix this by having T deduced rather than specifying myClassBase.

template <class T>
myArgs(T&& rhs) :
m_data(std::forward<T>(rhs))
{
}

If you want this function to only be valid if T is a myClassBase, you can write a trait to check it:

template <typename T>
struct isMyClassBaseImpl : std::false_type{};

template <typename T, typename D>
struct isMyClassBaseImpl<myClassBase<T,D>> : std::true_type{};

template <typename T>
using isMyClassBase = isMyClassBaseImpl<std::decay_t<T>>;

Then you can SFINAE it out:

template <class T, std::enable_if_t<isMyClassBase<T>::value>* = nullptr>
myArgs(T&& rhs) :
m_data(std::forward<T>(rhs))
{
}

How to add a parameter value when forwarding parameters to a variadic template function?

How to add hw to the forward list?

Simply

Bar<T>(hw, std::forward<Args>(args)...); 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

or if you want to move the hw to Bar()

#include <utility>      // std::move, std::forward

Bar<T>(std::move(hw), std::forward<Args>(args)...);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

or let the compiler deduce the type T

Bar(std::move(hw), std::forward<Args>(args)...); 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

for that, the Bar does not required the first template argument T

template<typename... Args>
void Bar(Args&&... args)
{
// ....
}

That being said, you might want to change the normal if statement with if constexpr for compile time branching, as follows:

#include <utility>      // std::move, std::forward
#include <type_traits> // std::is_same_v

template<typename T, typename... Args>
void Foo(Args&&... args)
{
if constexpr (std::is_same_v<T, std::string>)
{
std::string hw = "Hello, world!";
Bar(std::move(hw), std::forward<Args>(args)...);
}
else
{
Bar(std::forward<Args>(args)...);
}
}

Here is the complete demo

std::bind with variadic template and auto return type

This is definitely a gcc bug (filed 86826).

The solution is to just... not use std::bind(). There's hardly ever a reason to anyway. Lambdas are strictly superior:

template <typename... Args>
auto inv(Args... args) {
return [=]{ return inv_impl(args...); };
}


Related Topics



Leave a reply



Submit