How placeholders as _1 in a callback works? - c++

How the compiler interpret the symbol _1, and how the binding take place?
Consider the following example:
class A {
public:
boost::function<void (int x)> g;
};
class B {
public:
B() {}
static void foo(int i) { cout << "Hack: " << i <<endl; }
};
int main() {
A a;
a.g = boost::bind(B::foo,_1);
a.g(2);
return 0;
}
What magic happens internally in the line boost::bind(B::foo,_1);?
And how _1 is maped to the argument passed in the next line a.g(2);?
Output: Hack: 2

I will explain to the best of my ability. First and foremost, _1 is nothing but a global variable. There is nothing special about it in this regard, and it could be named anything else as well - placeholder1, or SergeyA. However, name like _1 is short, has well-understood meaning, and begins with _, which reduces likelihood of it clashing with other global names in the program.
The magic is in the type of this variable. It has a special type, which is reflected in generated bind* object. Later, when operator() is called, the type is recognized to take an argument from operator() arguments.
Here is some illustrating C++-like pseudocode, which is not correct, but is illustrative:
template<class F, class... ARG>
struct bound {
bound(F f, ARGS&&... args) : bound_args(args...), functor(f) { }
std::tuple<ARG...> bound_args;
template<class... T>
void operator()(T&&... args);
F f;
};
template<class F, class... T>
auto bind(F f, T&& args) {
return bound<std::remove_reference_t<T>...>(f, args...);
}
Now, let's introduce a placeholder type.
template<size_t N>
struct placeholder {
enum { position = N; };
template<class...T>
auto operator()(T&&... args) {
return std::get<position>(std::make_tuple(arg...));
}
};
placeholder<0> _1;
placeholder<1> _2;
So far so good. Now, let's see how the operator() actually works on bound object:
template<class... BOUND_ARGS>
template<class... CALL_ARGS>
void bound_object<BOUND_ARGS...>::operator() (CALL_ARGS&&... args) {
call_impl(args..., make_index_sequence<sizeof...(BOUND_ARGS)>{});
}
make_index_sequence here is needed to extract tuple values into function arguments, so do not pay too much attention to it. And here is call_impl;
template<class... BOUND_ARGS>
template<class... CALL_ARGS, size_t... ix>
void bound_object<BOUND_ARGS...>::call_impl(CALL_ARGS&&... args, std::index_sequence<ix...>) {
f(to_arg().(std::get<ix>(bound_args), args...)...);
}
And the last piece of puzzle is to_arg:
template<class B, class... ARGS>
auto to_arg(B&& b, ARGS... args) {
return b;
}
template<class... ARGS>
auto to_arg(placeholder<0> p, ARGS&&... args) {
return p(args);
}
template<class... ARGS>
auto to_arg(placeholder<1> p, ARGS&&... args) {
return p(args);
}
The whole of to_arg here is to give you either the bound argument or one of the supplied arguments, based on the bound argument type. In my example above, I used 3 overloads since you can partially specialize a function, but of course, it would make more sense to put it in a class and partially specialize the class.

Related

Template function does not work for pointer-to-member-function taking const ref

Lately I wrote a template function to solve some code repetitions. It looks like this:
template<class T, class R, class... Args>
R call_or_throw(const std::weak_ptr<T>& ptr, const std::string& error, R (T::*fun)(Args...), Args... args) {
if (auto sp = ptr.lock())
{
return std::invoke(fun, *sp, args...);
}
else
{
throw std::runtime_error(error.c_str());
}
}
int main() {
auto a = std::make_shared<A>();
call_or_throw(std::weak_ptr<A>(a), "err", &A::foo, 1);
}
This code works perfectly well for class A which looks like this:
class A {
public:
void foo(int x) {
}
};
But fails to compile for one like this:
class A {
public:
void foo(const int& x) {
}
};
Why is it so (by why I mean why it fails to deduce the type) and how (if it is possible at all) can I make this code work with references?
Live example
Args types cannot be deduced both as const& (from fun parameter declaration) and non-reference from args declaration. A simple fix is to use two separate template type parameter packs:
template<class T, class R, class... Args, class... DeclaredArgs>
R call_or_throw(
const std::weak_ptr<T>& ptr,
const std::string& error,
R (T::*fun)(DeclaredArgs...),
Args... args);
As a downside, I can imagine slightly longer error messages in case of bad usage.
Note that the template parameter Args's type is deduced as const int& on the 3rd function argument &A::foo, and deduced as int on the 4th function parameter 1. They don't match and cause deduction fails.
You can exclude the 4th parameter from deduction, e.g.
template<class T, class R, class... Args>
R call_or_throw(const std::weak_ptr<T>& ptr,
const std::string& error,
R (T::*fun)(Args...),
std::type_identity_t<Args>... args) {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
LIVE
PS: std::type_identity is supported since C++20; but it's quite easy to implement one.
Your issue is that you have conflict deductions for Args between:
R (T::*fun)(Args...)
Args... args
I suggest to have more generic code (no duplications between R (T::*fun)(Args...) and
const version R (T::*fun)(Args...) const and other alternative) with:
template<class T, class F, class... Args>
decltype(auto) call_or_throw(const std::weak_ptr<T>& ptr,
const std::string& error,
F f,
Args&&... args)
{
if (auto sp = ptr.lock())
{
return std::invoke(f, *sp, std::forward<Args>(args)...);
}
else
{
throw std::runtime_error(error.c_str());
}
}

Calling a variadic template function with a member function

Based on my previous question here Variadic template, function as argument
I have ended up with a simple class below, however how do I use std::invoke or some other method to call Tester::test with Tester::simple as argument? The examples provided at http://en.cppreference.com/w/cpp/utility/functional/invoke#Example were not very helpful for me and I tried many different ways of using std::invoke.
class Tester {
public:
template<typename F, typename... Args>
decltype(auto) test(F&& f, Args&&... args) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
int simple(int i) { return i; }
};
int main()
{
Tester t;
std::cout << t.test(t.simple, 3); // how do you modify this line such that the code compiles?
}
Thanks!
One way is to modify the definition of your test() member function like so:
class Tester {
public:
template<typename F, typename... Args>
decltype(auto) test(F&& f, Args&&... args) {
return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
}
int simple(int i) { return i; }
};
We can then pass a member function pointer to test(), with the instance on which the method should be called as the second argument, and then the function arguments themselves:
int main()
{
Tester t;
std::cout << t.test(&Tester::simple, t, 3);
}
The reason this works is because std::invoke has a special overload for pointers-to-members, such that
std::invoke(ptr-to-member, instance, args...);
is called as
(instance.*ptr-to-member)(args...);
which is exactly what we want in this case.
Note, that std::invoke is a part of C++ 17. In case if it is not available, one might implement test function so that it accepts a pointer-to-member-function and an instance of a class:
template<typename F, typename T, typename... Args>
decltype(auto) test(F f, T&& t, Args&&... args) {
return (std::forward<T>(t).*f)(std::forward<Args>(args)...);
}
Now test accepts a pointer-to-member-function as a first argument, an instance of a class as a second argument and an arbitrary number of additional arguments.
Then test might be called like:
Tester t;
std::cout << t.test(&Tester::simple, t, 42);
WANDBOX EXAMPLE
Just to mention yet another possibility, you could wrap the member function call in a lambda and capture the instance t. In C++14 we can use the generic lambda for that, so we don't have to specify the parameters explicitly.
#include <iostream>
#include <utility>
class Tester {
public:
template<typename F, typename... Args>
decltype(auto) test(F&& f, Args&&... args) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
int simple(int i) { return i; }
};
int main()
{
Tester t;
std::cout << t.test([&t] (auto&&... args) { return t.simple(std::forward<decltype(args)>(args)...); }, 3);
}

Variadic members in non-template class

I'm trying to write a class Invocation which has a templated constructor:
template<typename F>
class Invocation {
public:
template<typename... Args>
Invocation(F&& f, Args&&... args)
{ /* store f and args somewhere for later use */ }
...
};
Normally I would parameterize the Invocation class itself with both F and Args..., but in this case I need a uniform type for a given F, so I'm trying to find a way to store args... of any types inside a Invocation<F>, and to incur as little performance hit as possible. (This might not be the best design, but it can be an interesting exercise.)
One thought is to use virtual functions:
template<typename F>
class ArgsBase {
public:
// discard return value
virtual void invoke(F&& f) = 0;
};
template<typename F, typename... Ts>
class Args : public ArgsBase<F> {
public:
Args(Ts&&... args) : args_(std::forward<Ts>(args)...) {}
void invoke(F&& f) override
{
/* somehow call f with args_ (something like std::apply) */
...
}
private:
std::tuple<Ts&&...> args_;
};
And then in the Invocation<F> class, we can for example have an std::unique_ptr<ArgsBase<F>> member, which points to an Args<F, Ts...> object created in the Invocation<F> ctor. And we can call its invoke virtual method when needed.
This is just one random idea I came up with. Is there any other way to achieve this? Ideally without the overhead of virtual functions or anything like that?
UPDATE: Thanks to the comments/answers that suggest using std::function or lambdas. I should've made it clear that I'm actually interested in a more general case, i.e., the variadic stuff might not be arguments to a callable. It can be just anything that I want to store in a class whose type is not parameterized by the types of these stuff.
As mentioned in comment, I wouldn't worry about storing arguments by value. The compiler's copy-elision can be generous.
Particularly if you offer the class an r-value invoke:
#include <tuple>
template<typename F>
class ArgsBase {
public:
// discard return value
virtual void invoke(F&& f) const & = 0;
virtual void invoke(F&& f) && = 0;
};
template<typename F, class... FunctionArgs>
class Args : public ArgsBase<F> {
public:
template<class...Ts>
Args(Ts&&... args) : args_(std::forward<Ts>(args)...) {}
template<std::size_t...Is, class Tuple>
static void invoke_impl(F& f, std::index_sequence<Is...>, Tuple&& t)
{
f(std::get<Is>(std::forward<Tuple>(t))...);
}
void invoke(F&& f) const & override
{
invoke_impl(f,
std::make_index_sequence<std::tuple_size<tuple_type>::value>(),
args_);
/* somehow call f with args_ (something like std::apply) */
}
void invoke(F&& f) && override
{
invoke_impl(f,
std::make_index_sequence<std::tuple_size<tuple_type>::value>(),
std::move(args_));
/* somehow call f with args_ (something like std::apply) */
}
private:
using tuple_type = std::tuple<FunctionArgs...>;
tuple_type args_;
};
template<class Callable, class...MyArgs>
auto later(MyArgs&&...args) {
return Args<Callable, std::decay_t<MyArgs>...>(std::forward<MyArgs>(args)...);
}
void foo(const std::string&, std::string)
{
}
int main()
{
auto l = later<decltype(&foo)>(std::string("hello"), std::string("world"));
l.invoke(foo);
std::move(l).invoke(foo);
}
If you're trying to save a function call with its parameters for later invocation, you could use lambdas packaged in std::function objects:
template<typename F, typename ... Args>
std::function<void()> createInvocation(F f, const Args& ... args)
{
return [f,args...]() { f(args...); };
}
Then you could use it like this:
void myFunc(int a, int b)
{
std::cout << "Invoked: " << a + b << std::endl;
}
int main() {
auto invocation = createInvocation(myFunc, 1, 2);
invocation();
return 0;
}
UPDATE: If you wanted to create a generic non-templated container type, you can wrap a tuple into a type that itself derives from a non-templated type. The main problem then is accessing the underlying data. This can be solved by creating a static function dispatch table that for a given tuple type, redirects queries so that std::get, which requires a compile-time constant index template parameter, can instead be invoked with a dynamically provided function parameter. Here is an implementation that achieves this:
class GenericTupleContainer
{
public:
virtual const void* getItemAtIndex(size_t index) = 0;
};
template<typename ... T>
class TupleContainer : public GenericTupleContainer
{
public:
TupleContainer(T&& ... args)
: data(std::forward<T>(args)...)
{}
const void* getItemAtIndex(size_t index) override
{
if(index >= sizeof...(T))
throw std::runtime_error("Invalid index");
return dispatchTable[index](data);
}
private:
template<size_t index>
static const void* getItemAtIdx(const std::tuple<T...>& data)
{
return &std::get<index>(data);
}
using GetterFn = const void*(*)(const std::tuple<T...>&);
static GetterFn* initDispatchTable()
{
static GetterFn dispatchTable[sizeof...(T)];
populateDispatchTable<sizeof...(T)>(dispatchTable, std::integral_constant<bool, sizeof...(T) == 0>());
return dispatchTable;
}
static GetterFn* dispatchTable;
template<size_t idx>
static void populateDispatchTable(GetterFn* table, std::false_type);
template<size_t idx>
static void populateDispatchTable(GetterFn* table, std::true_type)
{
//terminating call - do nothing
}
std::tuple<T...> data;
};
template<typename ... T>
typename TupleContainer<T...>::GetterFn* TupleContainer<T...>::dispatchTable = TupleContainer<T...>::initDispatchTable();
template<typename ... T>
template<size_t idx>
void TupleContainer<T...>::populateDispatchTable(GetterFn* table, std::false_type)
{
table[idx-1] = &TupleContainer<T...>::template getItemAtIdx<idx-1>;
populateDispatchTable<idx-1>(table, std::integral_constant<bool, idx-1 == 0>() );
}
template<typename ... T>
auto createTupleContainer(T&& ... args)
{
return new TupleContainer<T...>(std::forward<T>(args)...);
}
Then you can use the above as follows:
int main() {
GenericTupleContainer* data = createTupleContainer(1, 2.0, "Hello");
std::cout << *(static_cast<const int*>(data->getItemAtIndex(0))) << std::endl;
std::cout << *(static_cast<const double*>(data->getItemAtIndex(1))) << std::endl;
std::cout << (static_cast<const char*>(data->getItemAtIndex(2))) << std::endl;
return 0;
}
As you can see from the above usage, you've achieved the aim of wrapping an arbitrary templated tuple into a non-templated type, in such a way that you can access the component members with a normal (function) index parameter instead of a template one. Now the return type of such a getter has to be universal, so I've chosen to use void* here, which is not ideal. But you can develop this idea to make this container give more useful information about the types of its data tuple members. Also, note that this does use a virtual function. With some further work you can get rid of this as well, although you won't be able to get rid of at least one function pointer lookup (i.e. the lookup in the dispatch table) - this is the price paid for gaining the flexibility of being able to use a runtime value to index into the tuple.

C++11/templates: Select the correct overloading of a function

In relation with this question, that perhaps is too much oversimplified, I give here a more complex example. The problem that I pretend is depicted with the following code:
// test3.cpp
using namespace std;
template<typename T>
struct exer
{
template<typename R, typename... rArgs, typename... pArgs>
R operator()(R(T::*f)(rArgs...), pArgs&&... args)
{
return (t.*f)(forward<pArgs>(args)...);
}
T t;
};
struct A
{
int addition() { return 0; }
template<typename... Args>
int addition(int a, Args... args) { return a + addition(args...); }
};
struct B
{
public:
template<typename... Args>
int addition(Args&&... args)
{
return m_e(&A::addition, forward<Args>(args)...);
}
private:
exer<A> m_e;
};
int main()
{
B b;
cout << b.addition(1, 2, 3, 4) << endl;
}
This problem here is, in the instantation of B::addition, the type of &A::addition isn't known because different overloads exists. Moreover, B::addition doesn't know also which overload must be used. This doesn't know the compiler until the function is called. But, in order to correctly specify wich overload must be used in exer<A>::operator(), I need to make a casting of &A::addition to cast it to the correct overload.
How can I extract the type of the correct overload of the target function?
Change the question. If you can make exer take a callable object instead of a pointer to member function, like so:
template<typename T>
struct exer
{
T t;
template<typename F, typename... pArgs>
auto operator()(F f, pArgs&&... args)
-> decltype(f(t, forward<pArgs>(args)...))
{
return f(t, forward<pArgs>(args)...);
}
};
Then you can do this instead:
struct B
{
public:
template<typename... Args>
int addition(Args&&... args)
{
struct Invoker {
auto operator()(A& a, Args&&... args) const
->decltype(a.addition(std::forward<Args>(args)...))
{ return a.addition(std::forward<Args>(args)...); }
};
return m_e(Invoker(), forward<Args>(args)...);
}
private:
exer<A> m_e;
};
Now selecting the correct A::addition is done by the compiler using the normal overload resolution rules.
Instead of Invoker you could use a lambda expression, which reduces some of the repetition:
return m_e( [](A& a, Args&&... as) {
return a.addition(forward<Args>(as)...);
},
forward<Args>(args)...);

Calling a function for each variadic template argument and an array

So I have some type X:
typedef ... X;
and a template function f:
class <typename T>
void f(X& x_out, const T& arg_in);
and then a function g:
void g(const X* x_array, size_t x_array_size);
I need to write a variadic template function h that does this:
template<typename... Args>
void h(Args... args)
{
constexpr size_t nargs = sizeof...(args); // get number of args
X x_array[nargs]; // create X array of that size
for (int i = 0; i < nargs; i++) // foreach arg
f(x_array[i], args[i]); // call f (doesn't work)
g(x_array, nargs); // call g with x_array
}
The reason it doesn't work is because you can't subscript args like that at runtime.
What is the best technique to replace the middle part of h?
And the winner is Xeo:
template<class T> X fv(const T& t) { X x; f(x,t); return x; }
template<class... Args>
void h(Args... args)
{
X x_array[] = { fv(args)... };
g(x_array, sizeof...(Args));
}
(Actually in my specific case I can rewrite f to return x by value rather than as an out parameter, so I don't even need fv above)
You could refactor or wrap f to return a new X instead of having it passed, since this would play pack expansion into the hand and make the function really concise:
template<class T>
X fw(T const& t){ X x; f(x, t); return x; }
template<class... Args>
void h(Args... args){
X xs[] = { fw(args)... };
g(xs, sizeof...(Args));
}
Live example.
And if you could change g to just accept an std::initializer_list, it would get even more concise:
template<class... Args>
void h(Args... args){
g({f(args)...});
}
Live example. Or (maybe better), you could also provide just a wrapper g that forwards to the real g:
void g(X const*, unsigned){}
void g(std::initializer_list<X> const& xs){ g(xs.begin(), xs.size()); }
template<class... Args>
void h(Args... args){
g({f(args)...});
}
Live example.
Edit: Another option is using a temporary array:
template<class T>
using Alias = T;
template<class T>
T& as_lvalue(T&& v){ return v; }
template<class... Args>
void h(Args... args){
g(as_lvalue(Alias<X[]>{f(args)...}), sizeof...(Args));
}
Live example. Note that the as_lvalue function is dangerous, the array still only lives until the end of the full expression (in this case g), so be cautious when using it. The Alias is needed since just X[]{ ... } is not allowed due to the language grammar.
If all of that's not possible, you'll need recursion to access all elements of the args pack.
#include <tuple>
template<unsigned> struct uint_{}; // compile-time integer for "iteration"
template<unsigned N, class Tuple>
void h_helper(X (&)[N], Tuple const&, uint_<N>){}
template<unsigned N, class Tuple, unsigned I = 0>
void h_helper(X (&xs)[N], Tuple const& args, uint_<I> = {}){
f(xs[I], std::get<I>(args));
h_helper(xs, args, uint_<I+1>());
}
template<typename... Args>
void h(Args... args)
{
static constexpr unsigned nargs = sizeof...(Args);
X xs[nargs];
h_helper(xs, std::tie(args...));
g(xs, nargs);
}
Live example.
Edit: Inspired by ecatmur's comment, I employed the indices trick to make it work with just pack expansion and with f and g as-is, without altering them.
template<unsigned... Indices>
struct indices{
using next = indices<Indices..., sizeof...(Indices)>;
};
template<unsigned N>
struct build_indices{
using type = typename build_indices<N-1>::type::next;
};
template <>
struct build_indices<0>{
using type = indices<>;
};
template<unsigned N>
using IndicesFor = typename build_indices<N>::type;
template<unsigned N, unsigned... Is, class... Args>
void f_them_all(X (&xs)[N], indices<Is...>, Args... args){
int unused[] = {(f(xs[Is], args), 1)...};
(void)unused;
}
template<class... Args>
void h(Args... args){
static constexpr unsigned nargs = sizeof...(Args);
X xs[nargs];
f_them_all(xs, IndicesFor<nargs>(), args...);
g(xs, nargs);
}
Live example.
Nice template as answer for first part of question:
template <class F, class... Args>
void for_each_argument(F f, Args&&... args) {
[](...){}((f(std::forward<Args>(args)), 0)...);
}
It's obvious: you don't use iteration but recursion. When dealing with variadic templates something recursive always comes in. Even when binding the elements to a std::tuple<...> using tie() it is recursive: It just happens that the recursive business is done by the tuple. In your case, it seems you want something like this (there are probably a few typos but overall this should work):
template <int Index, int Size>
void h_aux(X (&)[Size]) {
}
template <int Index, int Size, typename Arg, typename... Args>
void h_aux(X (&xs)[Size], Arg arg, Args... args) {
f(xs[Index], arg);
h_aux<Index + 1, Size>(xs, args...);
}
template <typename... Args>
void h(Args... args)
{
X xs[sizeof...(args)];
h_aux<0, sizeof...(args)>(xs, args...);
g(xs, sizeof...(args));
}
I think you won't be able to use nargs to define the size of the array either: Nothing indicates to the compiler that it should be a constant expression.
It's fairly simple to do with parameter pack expansion, even if you can't rewrite f to return the output parameter by value:
struct pass { template<typename ...T> pass(T...) {} };
template<typename... Args>
void h(Args... args)
{
const size_t nargs = sizeof...(args); // get number of args
X x_array[nargs]; // create X array of that size
X *x = x_array;
int unused[]{(f(*x++, args), 1)...}; // call f
pass{unused};
g(x_array, nargs); // call g with x_array
}
It should be possible just to write
pass{(f(*x++, args), 1)...}; // call f
but it appears g++ (4.7.1 at least) has a bug where it fails to order the evaluation of brace-initializer-list parameters as class initialisers. Array initialisers are OK though; see Sequencing among a variadic expansion for more information and examples.
Live example.
As an alternative, here's the technique mentioned by Xeo using a generated index pack; unfortunately it does require an extra function call and parameter, but it is reasonably elegant (especially if you happen to have an index pack generator lying around):
template<int... I> struct index {
template<int n> using append = index<I..., n>; };
template<int N> struct make_index { typedef typename
make_index<N - 1>::type::template append<N - 1> type; };
template<> struct make_index<0> { typedef index<> type; };
template<int N> using indexer = typename make_index<N>::type;
template<typename... Args, int... i>
void h2(index<i...>, Args... args)
{
const size_t nargs = sizeof...(args); // get number of args
X x_array[nargs]; // create X array of that size
pass{(f(x_array[i], args), 1)...}; // call f
g(x_array, nargs); // call g with x_array
}
template<typename... Args>
void h(Args... args)
{
h2(indexer<sizeof...(args)>(), std::forward<Args>(args)...);
}
See C++11: I can go from multiple args to tuple, but can I go from tuple to multiple args? for more information.
Live example.
Xeo is onto the right idea- you want to build some kind of "variadic iterator" that hides a lot of this nastiness from the rest of the code.
I'd take the index stuff and hide it behind an iterator interface modeled after std::vector's, since a std::tuple is also a linear container for data. Then you can just re-use it all of your variadic functions and classes without having to have explicitly recursive code anywhere else.