My problem is the following:
I have a class declared as such:
template<typename ReturnType, typename... Args>
class API
{
ReturnType operator()(Args... args)
{
// Get argument 0
// Get argument 1
}
};
I am in need of getting the arguments on by one, and so far the only way I've come up to (but I can not get it to work) is using std::get, as such:
std::get<0>(args);
Of course, this leads to a lot of errors.
I am new to variadic templates (and to C++11 at all) so I am quite lost at this point.
How could I get those arguments one by one?
Any help will be appreciated.
Capture the args in a temporary tuple (Live at Coliru):
ReturnType operator()(Args... args)
{
static_assert(sizeof...(args) >= 3, "Uh-oh, too few args.");
// Capture args in a tuple
auto&& t = std::forward_as_tuple(args...);
// Get argument 0
std::cout << std::get<0>(t) << '\n';
// Get argument 1
std::cout << std::get<1>(t) << '\n';
// Get argument 2
std::cout << std::get<2>(t) << '\n';
}
std::forward_as_tuple uses perfect forwarding to capture references to the args, so there should be no copying.
You can use recursion.
Here's an example:
#include <iostream>
template<typename ReturnType>
class API {
public:
template<typename Arg>
ReturnType operator()(Arg&& arg) {
// do something with arg
return (ReturnType) arg;
}
template<typename Head, typename... Tail>
ReturnType operator()(Head&& head, Tail&&... tail) {
// do something with return values
auto temp = operator()(std::forward<Head>(head));
return temp + operator()(std::forward<Tail>(tail)...);
}
};
int main() {
API<int> api;
auto foo = api(1, 2l, 2.0f);
std::cout << foo;
return 0;
}
A few helper templates can do that for you. I'm not aware of one in stl that does it directly, but I like to roll my own templates anyways:
namespace Internal {
template <size_t Pos, typename Arg, typename... Args>
struct Unpacker {
static auto unpack(Arg&&, Args&&... args) {
return Unpacker<Pos - 1, Args...>::unpack(std::forward<Args>(args)...);
}
};
template <typename Arg, typename... Args>
struct Unpacker<0, Arg, Args...> {
static auto unpack(Arg&& arg, Args&&...) { return std::forward<Arg>(arg); }
};
} // Internal
template <size_t Pos, typename... Args>
auto unpack(Args&&... args) {
return Internal::Unpacker<Pos, Args...>::unpack(std::forward<Args>(args)...);
}
Then you can use it like this:
auto unpacked0 = unpack<0>(1, "orange", 3.3f, "pie");
auto unpacked1 = unpack<1>(1, "orange", 3.3f, "pie");
auto unpacked2 = unpack<2>(1, "orange", 3.3f, "pie");
auto unpacked3 = unpack<3>(1, "orange", 3.3f, "pie");
// Will not compile, because there are only 4 arguments
// auto unpacked4 = unpack<4>(1, "orange", 3.3f, "pie");
fmt::print("{} {} {} {}\n", unpacked0, unpacked1, unpacked2, unpacked3);
Or in your case:
template<typename ReturnType, typename... Args>
class API {
ReturnType operator()(Args&&... args) {
// Get argument 0
auto& arg0 = unpack<0>(args...);
// Get argument 1
auto& arg1 = unpack<1>(args...);
}
};
Related
related post: How to combine std::bind(), variadic templates, and perfect forwarding?
Is there a way to bind a function with variadic tuples ? Here incorrect code indicating the intent:
// t is an instance of T
auto f = std::bind(&T::iterate,t,???);
// args is an instance of std::tuple<Args...> args;
std::apply(f,args);
(note: I am unsure "variadic tuple" to be the right terminology. Looking forward editing the post with your correction)
Since C++20 you can use std::bind_front:
template<class T>
void print (T val) {
std::cout << val << std::endl;
}
struct T {
template<class ... Args>
void iterate(Args... args) {
int temp[] = { (print(args),0)... };
}
};
// all happens here
template<class ... Args>
void foo(const tuple<Args...>& args) {
T t;
auto f = std::bind_front(&T::iterate<Args...>,&t);
std::apply(f,args);
}
// the call
int i = 1;
foo(std::make_tuple(i,i+1,"bind is cool"));
If you want to use old std::bind, you can provide your own placeholders to be generated from pack:
template<int N>
struct MyPlaceholder {};
namespace std {
template<int N>
struct is_placeholder<MyPlaceholder<N>> : public integral_constant<int, N> {};
}
template<class ... Args, size_t ... Indices>
void foo2helper(const tuple<Args...>& args, std::index_sequence<Indices...>) {
T t;
auto f = std::bind(&T::iterate<Args...>,&t, (MyPlaceholder<Indices+1>{})...);
std::apply(f,args);
}
template<class ... Args>
void foo2(const tuple<Args...>& args) {
foo2helper(args, std::make_index_sequence<sizeof...(Args)>{});
}
// the call
foo2(std::make_tuple(2.34,"only bind"));
Live demo
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);
Desired behavior
What I basically want is to create a function like this:
void func(std::string_view... args)
{
(std::cout << ... << args);
}
It should be able to work only with classes that are convertible to std::string_view.
Example:
int main()
{
const char* tmp1 = "Hello ";
const std::string tmp2 = "World";
const std::string_view tmp3 = "!";
func(tmp1, tmp2, tmp3, "\n");
return 0;
}
should print: Hello World!
Accomplished behavior
So far, I got here:
template<typename... types>
using are_strings = std::conjunction<std::is_convertible<types, std::string_view>...>;
template<typename... strings, class = std::enable_if_t<are_strings<strings...>::value, void>>
void func(strings... args)
{
(std::cout << ... << args);
}
int main()
{
const char* tmp1 = "Hello ";
const std::string tmp2 = "World";
const std::string_view tmp3 = "!";
func(tmp1, tmp2, tmp3, "\n");
return 0;
}
This actually works as expected, but there is still one big problem.
Problem
Only classes that are convertible to std::string_view can be used in this function and that's great.
However, even though classes are convertible, they are not converted to std::string_view!
This leads to needless copying of data(for example when std::string is passed as argument).
Question
Is there a way to force implicit conversion of variadic arguments to std::string_view?
Note
I know about std::initializer_list, but I would like to keep function call simple, without {}.
namespace impl{
template<class...SVs>
void func(SVs... svs){
static_assert( (std::is_same< SVs, std::string_view >{} && ...) );
// your code here
}
}
template<class...Ts,
std::enable_if_t< (std::is_convertible<Ts, std::string_view >{}&&...), bool > =true
>
void func( Ts&&...ts ){
return impl::func( std::string_view{std::forward<Ts>(ts)}... );
}
or somesuch.
#include <string_view>
#include <utility>
template <typename>
using string_view_t = std::string_view;
template <typename... Ts>
void func_impl(string_view_t<Ts>... args)
{
(std::cout << ... << args);
}
template <typename... Ts>
auto func(Ts&&... ts)
-> decltype(func_impl<Ts...>(std::forward<Ts>(ts)...))
{
return func_impl<Ts...>(std::forward<Ts>(ts)...);
}
DEMO
If you simply want to avoid needless copying of data, use a forward reference and then perform explicit casts (if still required). This way no data is copied but forwarded (in your main.cpp example, all params are passed as const references)
template <typename... strings,
class = std::enable_if_t<are_strings<strings...>::value, void>>
void func(strings&&... args) {
(std::cout << ... << std::string_view{args});
}
Not exactly what you asked... but if you can set a superior limit for a the length of args... (9 in following example) I propose the following solution: a foo<N> struct that inherit N func() static function that accepting 0, 1, 2, ..., N std::string_view.
This way, func() function are accepting what is convertible to std::string_view and all argument are converted to std::string_view.
That is exactly
void func(std::string_view... args)
{ (std::cout << ... << args); }
with the difference that func() functions are static methods inside foo<N>, that there is a limit in args... length and that there is a func() method for every supported length.
The full example is the following.
#include <string>
#include <utility>
#include <iostream>
#include <type_traits>
template <std::size_t ... Is>
constexpr auto getIndexSequence (std::index_sequence<Is...> is)
-> decltype(is);
template <std::size_t N>
using IndSeqFrom = decltype(getIndexSequence(std::make_index_sequence<N>{}));
template <typename T, std::size_t>
struct getType
{ using type = T; };
template <typename, typename>
struct bar;
template <typename T, std::size_t ... Is>
struct bar<T, std::index_sequence<Is...>>
{
static void func (typename getType<T, Is>::type ... args)
{ (std::cout << ... << args); }
};
template <std::size_t N, typename = std::string_view,
typename = IndSeqFrom<N>>
struct foo;
template <std::size_t N, typename T, std::size_t ... Is>
struct foo<N, T, std::index_sequence<Is...>> : public bar<T, IndSeqFrom<Is>>...
{ using bar<T, IndSeqFrom<Is>>::func ...; };
int main ()
{
const char* tmp1 = "Hello ";
const std::string tmp2 = "World";
const std::string_view tmp3 = "!";
foo<10u>::func(tmp1, tmp2, tmp3, "\n");
}
Make it a two-stage production:
template <class... Args>
std::enable_if_t<... && std::is_same<Args, std::string_view>()>
func(Args... args)
{
(std::cout << ... << args);
}
template <class... Args>
auto func(Args&&... args)
-> std::enable_if_t<... || !std::is_same<std::decay_t<Args>, std::string_view>(),
decltype(func(std::string_view(std::forward<Args>(args))...))>
{
func(std::string_view(std::forward<Args>(args))...);
}
For a set of N functions fs... each taking only a single argument, I would like to create an object which has a call operator taking N arguments args..., calls all functions fs(args)... and returns outputs as a tuple.
The basic class would look something like this. I have marked the places I do not know how to implement with ???.
template <class... Fs>
struct merge_call_object {
merge_call_object(Fs... _fs)
: fs(std::move(_fs)...) {}
template <class... Args>
auto operator()(Args &&... args) -> decltype(???){
???
}
std::tuple<Fs...> fs;
};
The expected usage of this object would be:
auto f1 = [](double x){ return 2*s; };
auto f2 = [](std::string const& s){ return s+" World!"; };
auto mco = merge_call_object{f1,f2};
// The following should yield std::tuple{42, "Hello World!"}
auto out = mco(21, "Hello ");
So far so good, doing the above is "easy" but I want that overloading for mco works as expected i.e. the following should compile and pass
static_assert(std::is_invocable_v<decltype(mco), double, std::string> == true);
static_assert(std::is_invocable_v<decltype(mco), double, double> == false);
The biggest challenge I see is how implement correctly the SFINAE -> decltype(???).
This question is inspired by the recent talk from CppCon Overloading: The Bane of All Higher-Order Functions, around 6:40 he talks about how to wrap a function into a lambda.
My implementation without the correct overload set, plus a small test on perfect forwarding.
#include <iostream>
#include <tuple>
#include <utility>
namespace detail {
template <std::size_t... I>
constexpr auto integral_sequence_impl(std::index_sequence<I...>) {
return std::make_tuple((std::integral_constant<std::size_t, I>{})...);
}
template <std::size_t N, typename Indices = std::make_index_sequence<N>>
constexpr auto integral_sequence = integral_sequence_impl(Indices{});
template <std::size_t N, typename Fun>
constexpr decltype(auto) apply_sequence(Fun &&fun) {
return std::apply(std::forward<Fun>(fun), detail::integral_sequence<N>);
}
} // namespace detail
template <class... Fs>
struct merge_call_object {
merge_call_object(Fs... _fs)
: fs(std::move(_fs)...) {}
template <class... Args>
auto operator()(Args &&... args) {
constexpr int N = sizeof...(Fs);
auto f = [&](auto I) { return std::get<I>(fs); };
auto arg = [&](auto I) -> decltype(auto) {
return std::get<I>(std::forward_as_tuple(std::forward<Args>(args)...));
};
return detail::apply_sequence<N>(
[&](auto... Is) { return std::forward_as_tuple(f(Is)(arg(Is))...); });
}
std::tuple<Fs...> fs;
};
struct Screamer {
Screamer() { std::cout << "Constructor!" << std::endl; }
Screamer(Screamer &&s) { std::cout << "Move constructor!" << std::endl; }
Screamer(Screamer const &s) { std::cout << "Copy constructor!" << std::endl; }
};
int main() {
auto f1 = [](auto &&x) -> decltype(auto) {
std::cout << "Calling f1" << std::endl;
return std::forward<decltype(x)>(x);
};
auto f2 = [](auto &&x) -> decltype(auto) {
std::cout << "Calling f2" << std::endl;
return std::forward<decltype(x)>(x);
};
auto mco = merge_call_object{f1, f2};
auto [s1, s2] = mco(Screamer{}, Screamer{});
return 0;
}
Since you have a direct one argument, one function mapping, all you really need is std::apply:
template <class... Args>
auto operator()(Args&&... args) {
return std::apply([&](Fs&... fs){
return std::tuple(fs(std::forward<Args>(args))...);
}, fs);
}
This will decay all of the types (that is, if some function/argument pair actually returns an int&, this will give you an int in that spot instead). This also isn't SFINAE-friendly.
A solution that is both SFINAE-friendly and maintains references just needs an extra dash of fold-expression:
template <class... Args,
std::enable_if_t<(std::is_invocable_v<Fs&, Args> && ...), int> = 0>
auto operator()(Args&&... args) {
return std::apply([&](Fs&... fs){
return std::tuple<std::invoke_result_t<Fs&, Args>...>(
fs(std::forward<Args>(args))...);
}, fs);
}
You have to use auto f() -> decltype(RET) { return RET; } way (Macro can be used to avoid the boiler plate :-/ and we can also handle noexcept).
Something like:
template <class... Fs>
struct merge_call_object {
private:
std::tuple<Fs...> fs;
private:
template <std::size_t... Is, typename Tuple>
auto call(std::index_sequence<Is...>, Tuple&& tuple)
-> decltype(std::make_tuple(std::get<Is>(fs)(std::get<Is>(std::forward<Tuple>(tuple)))...))
{
return std::make_tuple(std::get<Is>(fs)(std::get<Is>(std::forward<Tuple>(tuple)))...);
}
public:
merge_call_object(Fs... _fs)
: fs(std::move(_fs)...) {}
template <class... Args>
auto operator()(Args &&... args)
-> decltype(call(std::index_sequence_for<Fs...>(), std::forward_as_tuple(std::forward<Args>(args)...)))
{
return call(std::index_sequence_for<Fs...>(), std::forward_as_tuple(std::forward<Args>(args)...));
}
};
Demo
Given two or more example functions, is it possible to write templated code which would be able to deduce the arguments of a function provided as a template parameter?
This is the motivating example:
void do_something(int value, double amount) {
std::cout << (value * amount) << std::endl;
}
void do_something_else(std::string const& first, double & second, int third) {
for(char c : first)
if(third / c == 0)
second += 13.7;
}
template<void(*Func)(/*???*/)>
struct wrapper {
using Args = /*???*/;
void operator()(Args&& ... args) const {
Func(std::forward<Args>(args)...);
}
};
int main() {
wrapper<do_something> obj; //Should be able to deduce Args to be [int, double]
obj(5, 17.4); //Would call do_something(5, 17.4);
wrapper<do_something_else> obj2; //Should be able to deduce Args to be [std::string const&, double&, int]
double value = 5;
obj2("Hello there!", value, 70); //Would call do_something_else("Hello there!", value, 70);
}
In both uses of /*???*/, I am trying to work out what I could put there that would enable this kind of code.
The following doesn't appear to work, due to Args not being defined before its first use (along with what I have to assume are numerous syntax errors besides), and even if it did, I'm still looking for a version that doesn't require explicit writing of the types themselves:
template<void(*Func)(Args ...), typename ... Args)
struct wrapper {
void operator()(Args ...args) const {
Func(std::forward<Args>(args)...);
}
};
wrapper<do_something, int, double> obj;
With C++17 we can have auto template non-type parameters which make possible the Wrapper<do_something> w{} syntax 1).
As for deducing Args... you can do that with a specialization.
template <auto* F>
struct Wrapper {};
template <class Ret, class... Args, auto (*F)(Args...) -> Ret>
struct Wrapper<F>
{
auto operator()(Args... args) const
{
return F(args...);
}
};
Wrapper<do_something> w{};
w(10, 11.11);
1) Without C++17 it's impossible to have the Wrapper<do_something> w{} nice syntax.
The best you can do is:
template <class F, F* func>
struct Wrapper {};
template <class Ret, class... Args, auto (*F)(Args...) -> Ret>
struct Wrapper<Ret (Args...), F>
{
auto operator()(Args... args) const
{
return F(args...);
}
};
Wrapper<declype(do_something), do_something> w{};
With C++17, you can do this:
template <auto FUNC, typename = decltype(FUNC)>
struct wrapper;
template <auto FUNC, typename RETURN, typename ...ARGS>
struct wrapper<FUNC, RETURN (*)(ARGS...)> {
RETURN operator()(ARGS ...args) {
return FUNC(args...);
}
};
I've learned this technique from W.F.'s answer
Further improvement of C++17 version: less template parameters and proper noexcept annotation:
template<auto VFnPtr> struct
wrapper;
template<typename TResult, typename... TArgs, TResult ( * VFnPtr)(TArgs...)> struct
wrapper<VFnPtr>
{
TResult
operator ()(TArgs... args) const noexcept(noexcept((*VFnPtr)(::std::forward<TArgs>(args)...)))
{
return (*VFnPtr)(::std::forward<TArgs>(args)...);
}
};
With C++11 you can consider a templated make_wrapper helper function. However, with this approach the function pointer is not a template parameter. Instead, the function pointer is "carried" by the non-static data member called f_ in the following example:
#include <iostream>
void do_something(int value, double amount) {
std::cout << (value * amount) << std::endl;
}
void do_something_else(std::string const& first, double & second, int third) {
for(char c : first)
if(third / c == 0)
second += 13.7;
}
template<class Ret, class... Args>
using function_pointer = Ret(*)(Args...);
template<class Ret, class... Args>
struct wrapper {
using F = function_pointer<Ret, Args...>;
F f_;
explicit constexpr wrapper(F f) noexcept : f_{f} {}
template<class... PreciseArgs>// not sure if this is required
Ret operator()(PreciseArgs&&... precise_args) const {
return f_(std::forward<PreciseArgs>(precise_args)...);
}
};
template<class Ret, class... Args>
constexpr auto make_wrapper(
function_pointer<Ret, Args...> f
) -> wrapper<Ret, Args...> {
return wrapper<Ret, Args...>(f);
}
int main() {
constexpr auto obj = make_wrapper(do_something);
obj(5, 17.4);
constexpr auto obj2 = make_wrapper(do_something_else);
double value = 5;
obj2("Hello there!", value, 70);
return 0;
}
I am implementing a variadic template function because I want to make calls with up to 7 params. My calls go like this.
foo(1, 2, "msg", 4, 5.0);
or
foo(3, 4.1, "msg");
The first parameter identifies a protocol to use, and every parameter thereafter is what I would like to place in struct Msg.
struct Msg {
int proto;
string str;
int a;
int b;
double d;
};
The biggest problem I'm having is, I don't know how to get the remaining parameters after the first and store them. I'd like to use the first param to tell which struct members are to be populated. The part that confuses me is that each recursive call changes the function sig.
template<typename T>
T bar(T t) {
cout << __PRETTY_FUNCTION__ << endl;
return t;
}
template<typename T, typename... Args>
void foo(T value, Args... args)
{
cout << __PRETTY_FUNCTION__ << endl;
Msg msg;
msg.proto = value;
switch (value) {
case PROTO_A:
// when calling 'foo(1, 2, "msg", 4, 5.0)'
// 1 is proto and placed in struct Msg (msg.proto = value)
// but how to get the remaining params from args into struct Msg
foo(args...);
break;
case PROTO_B:
foo(args...);
break;
default:
break;
}
send_msg(msg);
}
You may use it without recursion:
Your specific fill method, with un-call fallback (using SFINAE and priority):
struct overload_priority_low {};
struct overload_priority_high : overload_priority_low {};
template<typename... Args>
auto Fill_ProtoA(Msg& msg, overload_priority_high, Args... args)
-> decltype(std::tie(msg.a, msg.str, msg.b, msg.d) = std::tie(args...), void())
{
std::tie(msg.a, msg.str, msg.b, msg.d) = std::tie(args...);
}
template<typename... Args> auto Fill_ProtoA(Msg& msg, overload_priority_low, Args... args)
{
throw std::runtime_error("Should not be called");
}
template<typename... Args>
auto Fill_ProtoB(Msg& msg, overload_priority_high, Args&&...args)
-> decltype(std::tie(msg.d, msg.str) = std::tie(args...), void())
{
std::tie(msg.d, msg.str) = std::tie(args...);
msg.a = 42;
msg.b = 42;
}
template<typename... Args> auto Fill_ProtoB(Msg& msg, overload_priority_low, Args... args)
{
throw std::runtime_error("Should not be called");
}
And then your dispatcher foo:
template<typename T, typename... Args>
void foo(T value, Args... args)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
Msg msg;
msg.proto = value;
switch (value) {
case PROTO_A: Fill_ProtoA(msg, overload_priority_high{}, args...); break;
case PROTO_B: Fill_ProtoB(msg, overload_priority_high{}, args...); break;
default: break;
}
send_msg(msg);
}
Demo
If I have correctly understood your problem, you want to build a variadic template function for which:
first parameter is a protocol number
following parameters can be of different types and aliment a struct
So I assume that you already have defined one struct Msg (depending on T ?) and that you are able to write the function that aliments the struct with one single param using the proto from the struct:
template <typename Arg>
void process(struct Msg& msg, Arg value) {
switch(msg.proto) {
case PROTO_A:
...
}
}
(maybe process(struct Msg<T>& msg, ...) but I leave that for you because you did not say how you process the individual parameters...
You can then write a recursive process version:
template <typename First first, typename... Args>
void process(struct Msg& msg, First first, Args ... args) {
process(msg, first);
if (sizeof...(args) > 0) {
process(msg, args...);
}
}
And your foo function can become:
template<typename T, typename... Args>
void foo(T value, Args... args)
{
cout << __PRETTY_FUNCTION__ << endl;
Msg msg;
msg.proto = value;
process(msg, args);
send_msg(msg);
}
Here's a generalization that might be of use to you. Here the arguments passed can be in any order (even empty). The compiler will deduce which arguments are assigned to which data members of the object in question (if at all).
#include <iostream>
#include <tuple>
#include <string>
constexpr std::size_t NOT_FOUND = -1;
using default_tuple = std::tuple<int, bool, double, char, std::string>;
template <typename, std::size_t> struct Pair;
template <typename Tuple, typename T, std::size_t Start, typename = void>
struct Find : std::integral_constant<std::size_t, NOT_FOUND> {};
template <typename Tuple, typename T, std::size_t Start>
struct Find<Tuple, T, Start, std::enable_if_t<(Start < std::tuple_size<Tuple>::value)>> {
static constexpr size_t value = std::is_same<std::remove_reference_t<T>, std::tuple_element_t<Start, Tuple>>::value ? Start : Find<Tuple, T, Start+1>::value;
};
template <typename T, typename... Pairs> struct SearchPairs;
template <typename T>
struct SearchPairs<T> : std::integral_constant<std::size_t, 0> {};
template <typename T, typename First, typename... Rest>
struct SearchPairs<T, First, Rest...> : SearchPairs<T, Rest...> {};
template <typename T, std::size_t I, typename... Rest>
struct SearchPairs<T, Pair<T,I>, Rest...> : std::integral_constant<std::size_t, I> {};
template <typename Tuple, typename ArgsTuple, std::size_t Start, std::size_t OriginalSize, typename Indices, typename LastIndices, typename = void>
struct ObtainIndices {
using type = Indices;
};
template <typename Tuple1, typename Tuple2, std::size_t Start, std::size_t OriginalSize, std::size_t... Is, typename... Pairs>
struct ObtainIndices<Tuple1, Tuple2, Start, OriginalSize, std::index_sequence<Is...>, std::tuple<Pairs...>,
std::enable_if_t<(Start < std::tuple_size<Tuple2>::value)>> {
using T = std::tuple_element_t<Start, Tuple2>;
static constexpr std::size_t start = SearchPairs<T, Pairs...>::value, // Searching through Pairs..., and will be 0 only if T is not found among the pairs. Else we start after where the last T was found in Tuple1.
index = Find<Tuple1, T, start>::value;
using type = std::conditional_t<(index < OriginalSize),
typename ObtainIndices<Tuple1, Tuple2, Start+1, OriginalSize, std::index_sequence<Is..., index>, std::tuple<Pair<T, index+1>, Pairs...>>::type, // Pair<T, index+1> because we start searching for T again (if ever) after position 'index'. Also, we must place Pair<T, index+1> before the Pairs... pack rather than after it because if a Pair with T already exists, that Pair must not be used again.
typename ObtainIndices<Tuple1, Tuple2, Start+1, OriginalSize, std::index_sequence<Is..., index>, std::tuple<Pair<T, index>, Pairs...>>::type // We add Pair<T, index> right before Pairs... since we want to use the default T value again if another T value is ever needed. Now this could clutter up the std::tuple<Pairs...> pack with many Pairs, causing more compile time, but there is no guarantee that Pair<T, index+1> is already there (since this default T value could be the first T value found).
>;
};
template <std::size_t I, std::size_t J, typename Tuple1, typename Tuple2>
void assignHelper (Tuple1&& tuple1, const Tuple2& tuple2) {
if (std::get<J>(tuple2) != std::tuple_element_t<J, Tuple2>()) // Make the assignment only if the right hand side is not the default value.
std::get<I>(std::forward<Tuple1>(tuple1)) = std::get<J>(tuple2);
}
template <typename Tuple1, typename Tuple2, std::size_t... Is, std::size_t... Js>
void assign (Tuple1&& tuple1, Tuple2&& tuple2, std::index_sequence<Is...>, std::index_sequence<Js...>) {
const int a[] = {(assignHelper<Is, Js>(tuple1, tuple2), 0)...};
static_cast<void>(a);
}
template <typename T, typename... Args>
void fillData (T& t, Args&&... args) {
auto s = t.tuple_ref();
std::tuple<Args...> a = std::tie(args...);
const auto tuple = std::tuple_cat(a, default_tuple{}); // Add default values for each type, in case they are needed if those types are absent in 'a'.
using IndexSequence = typename ObtainIndices<std::remove_const_t<decltype(tuple)>, decltype(s), 0, sizeof...(Args), std::index_sequence<>, std::tuple<>>::type;
assign (s, tuple, std::make_index_sequence<std::tuple_size<decltype(s)>::value>{}, IndexSequence{});
}
// Testing
class Thing {
int a, b;
char c;
double d;
std::string s;
int n;
public:
auto tuple_ref() {return std::tie(a, b, c, d, s, n);} // This (non-const) member function must be defined for any class that wants to be used in the 'fillData' function. Here 'auto' is std::tuple<int&, int&, char&, double&, std::string&, int&>.
void print() const {std::cout << "a = " << a << ", b = " << b << ", c = " << c << ", d = " << d << ", s = " << s << ", n = " << n << '\n';}
};
int main() {
Thing thing;
fillData (thing, 5, 12.8);
thing.print(); // a = 5, b = uninitialized, c = uninitialized, d = 12.8, s = uninitialized, n = uninitialized
fillData (thing, 3.14, 2, 'p', std::string("hi"), 5, 'k', 5.8, 10, std::string("bye"), 9); // Note that std::string("hi") must be use instead of "hi" because "hi" is of type const char[2], not std::string (then the program would not compile). See my thread http://stackoverflow.com/questions/36223914/stdstring-type-lost-in-tuple/36224017#36224006
thing.print(); // a = 2, b = 5, c = p, d = 3.14, s = hi, n = 10
fillData (thing, 4.8, 8, 'q', std::string("hello"));
thing.print(); // a = 8, b = 5, c = q, d = 4.8, s = hello, n = 10
fillData (thing, std::string("game over"));
thing.print(); // a = 8, b = 5, c = q, d = 4.8, s = game over, n = 10
}