I am trying to write a variadic function template. The first argument to the function is an integer index value. The rest of the (variable number of) arguments represent the variable number of arguments. This function must return the argument at the location index. For example, if function is invoked as
`find_item(1, -1, "hello", 'Z', 10.03)`
it must return "hello"
If invoked as
find_item(2, -1, "hello", 'Z', 10.03)
it must return 'Z'
If invoked as
find_item(3, -1, "hello", 'Z', 10.03, 'Q', 100)
it must return 10.03
etc....
I was trying something like the following code :
template <class T>
auto find_item(int inx, T val) { return val ;}
// GENERAL CASE
template <class T, class... Others>
auto find_item(int inx, T a1, Others ... others) {
if(inx==0) return a1 ;
else return print(inx-1, others...) ;
}
int main() {
cout<<find_item(1, -1, "hello", string("abvd"), 10.03)<<endl ; ;
}
This code does not compile because the return type not being uniform, can not be deduced. I want to know if there is any way that this can be achieved. Or is it an invalid use case all together. If this can be achieved, then how.
I want to know if there is any way that this can be achieved.
No.
In C/C++ (that are statically typed languages) the type returned from a function must depends from the types of the arguments, not from the values.
So the types returned from the following calls
find_item(1, -1, "hello", 'Z', 10.03);
find_item(2, -1, "hello", 'Z', 10.03);
find_item(3, -1, "hello", 'Z', 10.03);
must be the same.
Point.
You can get around this rule returning a std::variant
(that can contain values of different types), or a std::any
(that can contain generic values), but a type that is determined independently from the received value.
Different if you pass the index of type/value you want (the first argument, in your case) as a template parameter.
I mean: different if you call find_item()
as follows
find_item<1>(-1, "hello", 'Z', 10.03);
find_item<2>(-1, "hello", 'Z', 10.03);
find_item<3>(-1, "hello", 'Z', 10.03);
Now find_item<1>()
can return a char const *
, find_item<2>()
can return a char
and find_item<3>()
can return a double
.
This is because find_item<1>()
, find_item<2>()
and find_item<3>()
are different functions, so can have different return types.
But... this way... we've almost obtained the std::get<>()
that extract values from a std::tuple
.
Unfortunately you can use this solution only when the index (the template parameter) is known compile time.
In other words, you can't make something as follows
for ( auto i = 1 ; i < 4 ; ++i )
{ // .............NO! ---V
auto value = find_item<i>(-1, "hello", 'Z', 10.03);
}