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
Why Can't a Function Go After Main
What Is the Array Form of 'Delete'
Opencv Gtk+2.X Error - "Unspecified Error (The Function Is Not Implemented...)"
Converting Steady_Clock::Time_Point to Time_T
Disable Sleep Mode in Windows Mobile 6
Check If Class Is Derived from a Specific Class (Compile, Runtime Both Answers Available)
How to Increase Error Limit in Visual Studio
Immediate Exit of 'While' Loop in C++
What Happens If Main() Does Not Return an Int Value
C++ Copy Constructor Gets Called Instead of Initializer_List<>
Dealing with Floating Point Exceptions
Difference Between Console (/Subsystem:Console) and Windows (/Subsystem:Windows)
Why Do I Need to Include Both the iOStream and Fstream Headers to Open a File
Debug Assertion Failed! Expression: _Block_Type_Is_Valid
Understanding How Lambda Closure Type Has Deleted Default Constructor