Sorry for the inability to explain the primary Q in the title itself due to complexity of the problem.
Need to pass various types of std::pair
s to a method like below:
foo({1, 1} , {2, 2.2}, {3, "3"}); // 'first' is always `int`
However, I couldn't figure out a syntax for How to define foo()
using variadic templates?
This is more of a cosmetic change, where the intention is to avoid the boiler plate code. Hence below suggestion is ruled out:
template<typename... Args>
void foo (Args&&... args) { ... }
template<typename T> using pair = std::pair<int, T>;
foo(pair<int>{1, 1} , pair<double>{2, 2.2}, pair<std::string>{3, "3"});
For anyone who is interested, what I am going to do with various pair
s. An overloaded function will be invoked on all the args...
(using array trick) and all the second
values will be converted to a std::string
. For those who don't know the famous array trick:
const string array[] = { MyFunc(std::forward<Pairs>(pairs)) ... };
Similar (but not duplicate) question: Passing multiple std::pair to variadic template constructor using { }, { }
You can simply use this signature:
template<typename... Args>
void foo (std::pair<int, Args> ...args) { /*...*/}
or
template <typename ...Args> using pair = std::pair<int, Args...>;
Edit: As mentioned the question is about constructing std::pair withot providing template arguments and to convert second part of pair to string. with overloading the () operator can we write:
#include <iostream>
#include <vector>
#include <sstream>
struct Function{
template <typename T>
Function& operator()(int a, T b){
ss << b;
list.push_back(ss.str());
ss.str("");
return *this;
}
std::vector<std::string> get_string(){
return list;
}
std::vector<std::string> list;
std::stringstream ss;
};
int main(){
Function foo;
for(auto& s: foo(1, 3.0)(2,"foo")(3, 5.0f).get_string())
{
std::cout << s << std::endl;
}
}
If your intention is call foo()
in this way
foo({1, 1} , {2, 2.2}, {3, "3"});
using curly braces with values instead of explicit std::pair<int, int>{1,1}, std::pair<int, double>{1, 2.2}, ....
... I don't think it's possible.
If you can give up the curly braces, so calling foo()
in this way,
foo(1, 1 , 2, 2.2, 3, "3");
and constructing pair inside foo()
, you can do something like
#include <string>
#include <utility>
void foo ()
{
// do nothing ?
}
template <typename T2, typename ... Ts>
void foo (int v1, const T2 & v2, const Ts & ... vs)
{
std::pair<int, T2> p { v1, v2 };
// do something with p
foo(vs...);
}
int main()
{
foo(1, 1, 1, 2.2, 1, std::string("3"));
return 0;
}
But, frankly, I didn't like this solution, because isn't clear wich pairs are calling foo()
, so I think it's a better way use rahnema1's solution calling foo()
using make_pair()
foo(std::make_pair(1, 1), std::make_pair(1, 2.2),
std::make_pair(1, std::string("3")));
Closest I was able to get was a variadic template of pairs, in which the 2nd option is a template type, but the same type for every pair.
template<typename DataType, template<class, class> typename ...Pair>
void foo(const std::pair<int, DataType>& nextParam, const Pair<int, DataType>& ...remainingParams);
void foo({1, "a"}, {2, "b"}, {3, "c"}); // works
void foo({1, "a"}, {2, 3.14}, {3, 'A'}); // doesn't work
Perhaps there is a way to get the template parameter to be variadic. That said I'm a bit doubtful of that, you essentially need to be able to specify a single element of a pack or rather to use a single parameter from a pack without expanding it, but also acknowledging that it is in fact a pack.
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