std::async with shared pointer templated member functions - c++

I'm working on implementing multi-threading in a project, but am running into a wall when it comes to some more complicated uses of std::async. I want to call a member function on a templated object and pass in an argument as a parameter, but I can't get it to work when the template holds a shared pointer.
It's pretty simple to use std::async on member functions, and even templated member functions. I've seen plenty of answers around stack overflow for this specific usage. I've even run some test cases myself:
#include <thread>
#include <future>
#include <iostream>
class Bar
{
public:
Bar () {}
double data;
};
template <typename T>
class Foo
{
public:
Foo () {}
T set_data (T d) { data = d; return data; }
private:
T data;
};
#include "./foo.h"
#include <memory>
int main (int argc, char **argv)
{
/**
* Works fine
*/
Foo<int> foo1;
auto fut1 = std::async(std::launch::async, &Foo<int>::set_data, &foo1, 42);
fut1.wait();
std::cout << fut1.get() << std::endl;
return 0;
}
This example compiles perfectly fine in gcc 7.4.0 and returns 42 as expected.
My problem comes in when I use shared_ptr in the template. Using the same Foo and Bar classes from above:
#include "./foo.h"
#include <memory>
int main (int argc, char **argv)
{
/**
* Doesn't work
*/
auto foo2 = std::make_shared<Foo<std::shared_ptr<Bar>>>;
auto br = std::make_shared<Bar>;
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, &foo2, bar);
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}
I get this error when compiling g++ -pthread test.cpp -o test
test.cpp: In function ‘int main(int, char**)’:
test.cpp:20:94: error: no matching function for call to ‘async(std::launch, std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*)(std::shared_ptr<Bar>), Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*&)())’
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, &foo2, bar);
^
In file included from ./foo.h:2:0,
from test.cpp:1:
/usr/include/c++/7/future:1712:5: note: candidate: template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_Args>::type ...)>::type> std::async(std::launch, _Fn&&, _Args&& ...)
async(launch __policy, _Fn&& __fn, _Args&&... __args)
^~~~~
/usr/include/c++/7/future:1712:5: note: template argument deduction/substitution failed:
/usr/include/c++/7/future: In substitution of ‘template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_Args>::type ...)>::type> std::async(std::launch, _Fn&&, _Args&& ...) [with _Fn = std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*)(std::shared_ptr<Bar>); _Args = {Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*&)()}]’:
test.cpp:20:94: required from here
/usr/include/c++/7/future:1712:5: error: no type named ‘type’ in ‘class std::result_of<std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*(Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*)()))(std::shared_ptr<Bar>)>’
/usr/include/c++/7/future:1745:5: note: candidate: template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_Args>::type ...)>::type> std::async(_Fn&&, _Args&& ...)
async(_Fn&& __fn, _Args&&... __args)
^~~~~
/usr/include/c++/7/future:1745:5: note: template argument deduction/substitution failed:
/usr/include/c++/7/future: In substitution of ‘template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_Args>::type ...)>::type> std::async(_Fn&&, _Args&& ...) [with _Fn = std::launch; _Args = {std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*)(std::shared_ptr<Bar>), Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*&)()}]’:
test.cpp:20:94: required from here
/usr/include/c++/7/future:1745:5: error: no type named ‘type’ in ‘class std::result_of<std::launch(std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*)(std::shared_ptr<Bar>), Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*)())>’
I thought this maybe was because the reference & wasn't working in the proper order with all those angle brackets for the templates, so I tried using some parentheses:
#include "./foo.h"
#include <memory>
int main (int argc, char **argv)
{
/**
* Doesn't work
*/
Foo<std::shared_ptr<Bar>> foo2;
Bar bar;
auto fut2 = std::async(std::launch::async, &(Foo<std::shared_ptr<Bar>>::set_data), &foo2, bar);
fut2.wait();
std::cout << fut2.get().data << std::endl;
return 0;
}
Which results in a shorter error which I also don't understand.
test.cpp: In function ‘int main(int, char**)’:
test.cpp:20:75: error: invalid use of non-static member function ‘T Foo<T>::set_data(T) [with T = std::shared_ptr<Bar>]’
auto fut2 = std::async(std::launch::async, &(Foo<std::shared_ptr<Bar>>::set_data), &foo2, bar);
I am confused why the shared pointers all of a sudden make a difference, and I'm guessing it has to do with type deduction? Any help is appreciated.
EDIT
Thanks to those that responded, here is the solution. The parentheses are not required, and some shared_ptrs were missing.
#include "./foo.h"
#include <memory>
int main (int argc, char **argv)
{
Foo<std::shared_ptr<Bar>> foo2;
auto bar = std::make_shared<Bar>(2.5);
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data), &foo2, bar;
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}

There are some issues, I think that using a lambda might help you clarify what is going on:
int main (int argc, char **argv)
{
Foo<std::shared_ptr<Bar>> foo2;
Bar bar;
auto op = [foo2, bar]() mutable {return foo2.set_data(std::make_shared<Bar>(bar));};
auto fut2 = std::async(std::launch::async, op);
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}
You have to pass to the set_data a shared_ptr to Foo. Secondly, the set_data is not const-qualified, so you need a mutable lambda.
Lastly, the future, when returning though get(), will give you a shared_ptr to Bar so you need the operator -> .
You can make the code more efficient moving Foo2 and Bar inside the lambda, but I am trying to keep the answer simple, in particular because I do not know if you want, in your use case to re-use Foo2 and Bar, but you can consider moving inside the lambda.
Regarding your specific code, the following is compiling in g++ 9.1 with C++14, see https://godbolt.org/z/DFZLtb
int main (int argc, char **argv)
{
Foo<std::shared_ptr<Bar>> foo2;
Bar bar;
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, &foo2, std::make_shared<Bar>());
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}
You need to provide a shared_ptr<Bar>as argument and not a Bar and you need to remove the parenthesis around Foo<std::shared_ptr<Bar>>::set_data.

You just have some typos in your code, in first shared_ptr example you pass shared_ptr<Foo> instead of raw ptr Foo* to your function. In the second example first argument Foo* is correct, but second one is Bar instead of shared_ptr<Bar>. Here you have the working example:
class Bar
{
public:
Bar () {}
double data;
};
template <typename T>
class Foo
{
public:
Foo () {}
T set_data (T d) { data = d; return data; }
private:
T data;
};
#include <future>
TEST(xxx, yyy) {
Foo<std::shared_ptr<Bar> > foo;
auto bar = std::make_shared<Bar>();
bar->data = 42;
auto futureResult = std::async(std::launch::async,
&Foo<std::shared_ptr<Bar> >::set_data, &foo, bar);
std::cout << futureResult.get()->data << std::endl;
}
As a side note, if you need to run async operation on some data inside your Foo class, better provide the interface that executes this async operation inside your class and returns the future.
std::future<T> runAsyncOper(const T& data);

Your first example with the shared pointer doesn't pass a shared pointer to std::async as a last parameter, it passes a pointer to function (you didn't add the parentheses)
int main()
{
/**
* Works :)
*/
Foo<std::shared_ptr<Bar>> foo2;
auto br = std::make_shared<Bar>();
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, &foo2, br);
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}

Problem is that you passed wrong types of arguments to std::async and used incorrectly std::make_shared.
Minimal modification to your code:
auto foo2 = std::make_shared<Foo<std::shared_ptr<Bar>>>();
auto bar = std::make_shared<Bar>();
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, foo2, bar);
fut2.wait();
std::cout << fut2.get()->data << std::endl;
https://wandbox.org/permlink/3YXG56ahFKrZs8GB

Related

std::bind() throwing error when this is not passed

I am trying to understand std::bind(). I am trying to understand the code in the post https://riptutorial.com/cplusplus/example/7541/std--function-used-with-std--bind.
Code is as below.
#include <iostream>
#include <functional>
using namespace std;
class A
{
public:
std::function<void(int, const std::string&)> m_CbFunc = nullptr;
void foo()
{
if (m_CbFunc)
{
m_CbFunc(100, "event fired");
}
}
};
class B
{
public:
B(int x) : y(x)
{
auto aFunc = std::bind(&B::eventHandler, this, std::placeholders::_1, std::placeholders::_2);
anObjA.m_CbFunc = aFunc;
}
void eventHandler(int i, const std::string& s)
{
std::cout << s << ": " << i << std::endl;
}
void DoSomethingOnA()
{
anObjA.foo();
}
int y;
A anObjA;
};
int main(int argc, char *argv[])
{
B anObjB(4);
anObjB.DoSomethingOnA();
}
I couldn't understand why we are using this in bind call
auto aFunc = std::bind(&B::eventHandler, this, std::placeholders::_1, std::placeholders::_2)
eventHandler is taking 2 parameters and we are binding with placeholders. Not sure why do we need to pass this. If I remove this, I am getting below error.
/usr/include/c++/6/functional:1286:7: error: static assertion failed: Wrong number of arguments for pointer-to-member
static_assert(_Varargs::value
^~~~~~~~~~~~~
main.cpp: In constructor ‘B::B(int)’:
main.cpp:34:27: error: no match for ‘operator=’ (operand types are ‘std::function&)>’ and ‘std::_Bind&)>(std::_Placeholder<1>, std::_Placeholder<2>)>’)
anObjA.m_CbFunc = aFunc;
^~~~~
In file included from main.cpp:10:0:
/usr/include/c++/6/functional:1929:7: note: candidate: std::function<_Res(_ArgTypes ...)>& std::function<_Res(_ArgTypes ...)>::operator=(const std::function<_Res(_ArgTypes ...)>&) [with _Res = void; _ArgTypes = {int, const std::basic_string, std::allocator >&}]
operator=(const function& __x)
^~~~~~~~
The this is needed because eventHandler() is not a static method. std::bind() is used specifically when you want to use non-static methods of your class.
Note that personally, I find it ugly and don't like using it. I use lambdas instead.
anObjA.m_CbFunc = [=](int i, const std::string&s) { eventHandler(i,s); };
Even though the syntax for lambdas is kind of ugly, I don't think it's as ugly or obscure as bind. But that's just my preference.

auto-returning functions and template instantiation

While writing some template code, I ran into <unresolved overloaded function type> errors which can be reduced to the following.
template <int N>
auto bar()
{
return N;
}
int main(int, char* [])
{
auto foo = [] (auto func) {
return func();
};
foo(bar<3>);
}
With the errors being:
unresolved_overload.cpp: In function 'int main(int, char**)':
unresolved_overload.cpp:26:28: error: no match for call to '(main(int, char**)::<lambda(auto:1)>) (<unresolved overloaded function type>)'
std::cout << foo(bar<3>) << std::endl;
^
unresolved_overload.cpp:21:29: note: candidate: template<class auto:1> constexpr main(int, char**)::<lambda(auto:1)>::operator decltype (((const main(int, char**)::<lambda(auto:1)>*)((const main(int, char**)::<lambda(auto:1)>* const)0))->operator()(static_cast<auto:1&&>(<anonymous>))) (*)(auto:1)() const
auto foo = [] (auto func) {
^
unresolved_overload.cpp:21:29: note: template argument deduction/substitution failed:
unresolved_overload.cpp:26:28: note: couldn't deduce template parameter 'auto:1'
std::cout << foo(bar<3>) << std::endl;
^
unresolved_overload.cpp:21:29: note: candidate: template<class auto:1> main(int, char**)::<lambda(auto:1)>
auto foo = [] (auto func) {
^
unresolved_overload.cpp:21:29: note: template argument deduction/substitution failed:
unresolved_overload.cpp:26:28: note: couldn't deduce template parameter 'auto:1'
std::cout << foo(bar<3>) << std::endl;
If we replace the auto-return with the explicit return type, int, the example will compile fine.
Why does auto-return run into these issues? I looked into template argument deduction and substitution but the search was largely unfruitful. I thought it might have something to do with the order of template instantiation / etc but couldn't make too much sense of it...
Per AndyG's suggestion, I found the same issue on GCC's bug list. Bug 64194. First reported in 2014. Thus the conclusion seems to be that this is a GCC bug and thankfully not another special case for templates.
Working around this just requires having something else to trigger the instantiation (e.g. assign to a variable, a using declaration).
Try this:
template <typename func>
auto bar(func&& f)->decltype(f())
{
return f();
}
int main()
{
int i = 100;
auto f = [=]()
{
return i;
};
bar(f);
return 0;
}

main()::__lambda1 is not an accessible base of std::_Tuple_impl<1ul, main()::__lambda1>

Take the following:
#include <utility>
#include <functional>
#include <iostream>
struct FooType
{
FooType(std::tuple<std::function<void()>, std::function<void()>> t)
{
std::get<0>(t)();
std::get<1>(t)();
}
};
int main()
{
FooType foo(
std::make_tuple(
[]() { std::cout << "a\n"; },
[]() { std::cout << "b\n"; }
)
);
}
It builds and runs fine with GCC 4.9 and higher, but with GCC 4.8 (which is my build system) the following compiler error results:
In file included from main.cpp:2:0:
/usr/include/c++/4.8/functional: In substitution of 'template<class _Res, class ... _ArgTypes> template<class _Functor> using _Invoke = decltype (std::__callable_functor(declval<_Functor&>())((declval<_ArgTypes>)()...)) [with _Functor = std::_Tuple_impl<1ul, main()::__lambda1>; _Res = void; _ArgTypes = {}]':
/usr/include/c++/4.8/functional:2257:9: required from 'constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(std::_Tuple_impl<_Idx, _UHead, _UTails ...>&&) [with _UHead = main()::__lambda0; _UTails = {main()::__lambda1}; long unsigned int _Idx = 0ul; _Head = std::function<void()>; _Tail = {std::function<void()>}]'
/usr/include/c++/4.8/tuple:556:60: required from 'constexpr std::tuple<_T1, _T2>::tuple(std::tuple<_U1, _U2>&&) [with _U1 = main()::__lambda0; _U2 = main()::__lambda1; <template-parameter-2-3> = void; _T1 = std::function<void()>; _T2 = std::function<void()>]'
main.cpp:21:5: required from here
/usr/include/c++/4.8/functional:2181:71: error: 'main()::__lambda1' is not an accessible base of 'std::_Tuple_impl<1ul, main()::__lambda1>'
using _Invoke = decltype(__callable_functor(std::declval<_Functor&>())
^
Presumably I've hit a "bug" in GCC 4.8's experimental C++11 implementation, but I can't find any discussion about it online. Is this issue familiar to anyone? Is there a cheap workaround?
Passing std::function in tuples is core to the design I've just created — shame on me for building it in Coliru without switching to GCC 4.8 specifically until the end!
Creating a tuple with explicit template arguments works as a workaround:
#include <utility>
#include <functional>
#include <iostream>
struct FooType
{
FooType(std::tuple<std::function<void()>, std::function<void()>> t)
{
std::get<0>(t)();
std::get<1>(t)();
}
};
int main()
{
FooType foo(
std::make_tuple
<
std::function<void()>,
std::function<void()>
>(
[]() { std::cout << "a\n"; },
[]() { std::cout << "b\n"; }
)
);
}

C++ polymorphism with variadic function parameter

I am sharing with you an issue that I got with a class using variadic function parameters. It is the class Thread shown in the following code. It is a wrapper of std::thread in order to use the function pattern.
I wanted to use polymorphism with this function in inheriting the class Thread into a new class, Functor, but gcc returns the errors bellow:
#include <thread>
#include <iostream>
using namespace std;
template<class... Args>
class Thread
{
public:
virtual void operator()(Args...) = 0;
void run(Args... args)
{
std::thread t(std::forward< Thread<Args...> >(*this), std::forward<Args>(args)...);
t.join();
}
};
template<class... Args>
class Functor : public Thread<Args...>
{
public:
// generates the errors bellow
virtual void operator()(Args... /*args*/)
{
}
// doesnot work since the pure virtual function wants another prototype of function.
// void operator()(int)
// {
// }
};
int main()
{
int a = 12;
Functor<int> f;
f.run(ref(a));
return 0;
}
from t-Thread-args2.cpp:1:
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple: In instantiation of ‘struct std::_Head_base, false>’:
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:215:12: required from ‘struct std::_Tuple_impl, int>’
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:507:11: required from ‘class std::tuple, int>’
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/functional:1601:39: required from ‘struct std::_Bind_simple(int)>’
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/thread:133:9: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = Thread; _Args = {int}]’
t-Thread-args2.cpp:14:83: required from ‘void Thread::run(Args ...) [with Args = {int}]’
t-Thread-args2.cpp:42:17: required from here
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:166:13: error: cannot declare field ‘std::_Head_base, false>::_M_head_impl’ to be of abstract type ‘Thread’
t-Thread-args2.cpp:7:7: note: because the following virtual functions are pure within ‘Thread’:
t-Thread-args2.cpp:10:18: note: void Thread::operator()(Args ...) [with Args = {int}]
I dont really understand the error since the pure virtual function was well defined in the deriveted class. However, in moving the function run() into the derivated class (Functor) it works.
Thanks in advance,
Caner
As per [thread.thread.constr]§3, the type of the first argument of the std::thread constructor is F&&, with the requirement that F is MoveConstructible. In your case, F is Thread, which is not MoveConstructible.
In other words, the std::thread needs to store the functor by value, and you're forwarding the functor as Thread, which is abstract.
The problem is:
std::forward< Thread<Args...> >(*this)
which tries to copy the Thread sub-object. Luckily it's abstract, so you get a compile error rather than unexpected runtime behaviour.
You want a reference wrapper instead:
std::ref(*this)
I considered the multiple advice provided by the participants to this topic including the use of std::ref and would like to share with you the working code version solving the issues I got with the previous code.
#include <thread>
#include <iostream>
using namespace std;
template<class... Args>
class Thread
{
public:
virtual void operator()(Args...) = 0;
void run(Args... args)
{
std::thread t(std::ref(*this), args...);
t.join();
}
};
template<class... Args>
class Functor : public Thread<Args...>
{
public:
void operator()(int)
{
while (1)
{
cout << "42 "; cout.flush();
}
}
};
int main()
{
int a = 12;
Functor<int> f;
f.run(ref(a));
return 0;
}
Thanks again.

Converting std::function<void(string, string)> to a generic std::function<void()>

I'm trying somme features of c++0x (under gcc 4.5):
I know it's possible to convert a std::function<void(string, string)> to std::function<void()> when arguments are specified at compilation; but is it possible when arguments are submitted at runtime ?
#include <iostream>
#include <utility>
#include <string>
using namespace std;
using namespace placeholders;
class Print{
public:
void print1(string s1, string s2){ cout<<"s1 : "<<s1<<" s2 : "<<s2<<endl;}
void print2(string s1){ cout<<"s1 : "<<s1<<endl;}
};
Print p = Print();
function<void(string, string)> f1(bind(&Print::print1, &p, _1, _2));
function<void()> f = f1;
I get those errors :
/usr/include/c++/4.5/functional:2103:6: instantiated from ‘std::function<_Res(_ArgTypes ...)>::function(_Functor, typename std::enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::type) [with _Functor = std::function<void(std::basic_string<char>, std::basic_string<char>)>, _Res = void, _ArgTypes = {}, typename std::enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::type = std::function<void()>::_Useless]’
../src/Cpp0x_test.cpp:345:34: instantiated from here
/usr/include/c++/4.5/functional:1713:9: error: no match for call to ‘(std::function<void(std::basic_string<char>, std::basic_string<char>)>) ()’
/usr/include/c++/4.5/functional:2111:5: note: candidate is: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = void, _ArgTypes = {std::basic_string<char>, std::basic_string<char>}]
Actually I need to do :
function<void(string, string)> f1(bind(&Print::print1, &p, _1, _2));
function<void(string)> f2(bind(&Print::print2, &p, _1));
function<void()> fx1 = f1;
function<void()> fx2 = f2;
std::vector<function<void()> > vec;
vec.push_back(fx1);
vec.push_back(fx2);
//then, later
function<void()> call1 = vec[0];
function<void()> call2 = vec[1];
call1("test1", "test2");
call2("test3");
The question doesn't really make sense.
I know it's possible to convert a std::function<void(string, string)>
to std::function<void()> when arguments are specified at compilation;
but is it possible when arguments are submitted at runtime ?
If you're talking about doing this to set the arguments "at compilation":
string arg1,arg2;
function<void()> f = bind(f1,arg1,arg2); // f = [=] { f1(arg1,arg2); };
this is actually doing the binding at runtime. Whatever value those arguments have when bind is called, even if they are set at runtime, say, from user input, the calling f() will use those runtime values.
Perhaps you mean that the above code binds f1 to the value of arg1 and arg2 at the time bind is called, and that changing the values of the objects used in bind later on doesn't affect the values used in calls to f(). There's a way around that:
string arg1,arg2;
function<void()> f =
bind(f1,std::ref(arg1),std::ref(arg2)); // f = [&,f1] { f1(arg1,arg2); };
This causes f to hold references to the objects instead of just the static value used at the time bind is called. You can now assign new values to arg1 and arg2 and when f() is called the new values will be used. Note that you have to make sure that the references held by f remain valid and don't become dangling references so long as f can still be called.
function<void(string)> foo = [](string s){ cout << s; };
string arg = "Hello,";
function<void()> bar = bind(foo,ref(arg)); // bar = [=,&arg] { foo(arg); };
bar(); // prints "Hello,"
arg = " World!"
bar(); // prints " World!"
Its possible using bind aswell:
string arg1, arg2;
function<void()> f(bind(f1, arg1, arg2));
f(); // calls f1(arg1, arg2) with their values at the time of bind
Let's see if I understand your requirement.
Why don't you just store the arguments in a vector instead of the functions?
std::vector<std::tuple<std::string,std::string>> v;
v.push_back(std::make_tuple("a", "b")); // repeat
// Later that day...
for(auto& t : v) {
f(get<0>(t), get<1>(t));
}