Consider two function calls
foo({"a", 1}, {"b", "value"});
foo({"a", 1}, {"b", "value"}, {"c", 1.0});
Is there a way to write function foo
for arbitrary number of argument pairs?
I was thinking something along the lines
template <typename... Args>
void foo(std::pair<const char*, Args>&&...);
which unfortunately does not work.
gcc fails with an error:
error: too many arguments to function 'void foo(std::pair<const char*, Args>&& ...) [with Args = {}]'
foo({"aa", 1});
Try to simplify a bit your example and consider this:
#include<utility>
template<typename T>
void foo(std::pair<char*, T>) {}
int main() {
foo({"a", 1});
}
It doesn't compile, as you can see.
The problem is that { "a", 1 }
is not a std::pair
, even if you can construct one from it as it follows:
#include<utility>
void foo(std::pair<char*, int>) {}
int main() {
foo({"a", 1});
}
The error is quite clear:
couldn't infer template argument 'T'
Why can't you?
Te compiler could construct such a pair once T
is known. Anyway, T
must be deduced and the compiler cannot do that because { "a", 1 }
is not a pair from which it can be deduced.
Anyway, { "a", 1 }
can be converted to a pair, in the specific case to a specialization of std::pair<char *, T>
, but first of all T
must be deduced.
Deduced from what? A pair, of course, but you don't have a pair yet.
And so on, in a loop.
Let's discuss now your attempt to do something similar that involves a variadic template: it goes without saying that, if even the simpler example shown above doesn't compile, its variadic extension (if any) would not compile as well for more or less the same reason.
Is there a way to write function foo for arbitrary number of argument pairs?
I would say no, unless you use pairs as arguments for foo
.
It follows a minimal, working example:
#include<utility>
template <typename... Args>
void foo(std::pair<const char*, Args>&&...) {}
int main() {
foo(std::make_pair("a", 1), std::make_pair("b", "value"));
}
If you prefer, you can also deduce the first argument, as long as its type is fixed:
#include<utility>
template <typename T, typename... Args>
void foo(std::pair<T, Args>&&...) {}
int main() {
foo(std::make_pair("a", 1), std::make_pair("b", "value"));
}
Otherwise you can do this if it's not fixed:
#include<utility>
template <typename... First, typename... Second>
void foo(std::pair<First, Second>&&...) {}
int main() {
foo(std::make_pair("a", 1), std::make_pair(0, "value"));
}
Is there a way to write function foo for arbitrary number of argument pairs?
There are some solutions based on variadic templates but arguments must be pairs to allow compiler to deduce types. Then something like this might work:
template<typename... Args>
void foo() {}
template<typename T, typename U, typename... Args>
void foo(const std::pair<T, U>& p, Args... args) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
foo(args...);
}
So for:
foo(std::make_pair("a", 1), std::make_pair("b", "value"), std::make_pair("c", 1.0));
The output (with clang 3.8) is:
void foo(const std::pair<T, U> &, Args...) [T = const char *, U = int, Args = <std::__1::pair<const char *, const char *>, std::__1::pair<const char *, double>>]
void foo(const std::pair<T, U> &, Args...) [T = const char *, U = const char *, Args = <std::__1::pair<const char *, double>>]
void foo(const std::pair<T, U> &, Args...) [T = const char *, U = double, Args = <>]
Here is the full working example.
To expand a bit on Edgar Rokyan's answer, you can move the pair creation into the foo
function:
template<typename... Args>
void foo() {}
// Forward declaration
template<typename U, typename... Args>
void foo(const char * str, U u, Args... args);
// When given a pair
template<typename U, typename... Args>
void foo(const std::pair<const char *, U>& p, Args... args) {
std::cout << p.first << " = " << p.second << std::endl;
foo(args...);
}
// when given a C string and something else, make a pair
template<typename U, typename... Args>
void foo(const char * str, U u, Args... args) {
foo(std::make_pair(str, u), args...);
}
Then you can call it like:
foo("hi", 42,
"yo", true,
std::make_pair("Eh", 3.14),
"foo", false,
some_pair);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With