Reputation: 3099
The following minimal example compiles with g++ -std=c++11 -Wall tuple.cpp -o tuple
:
#include <tuple>
#include <iostream>
template<int i>
char get_elem_i(std::tuple<char, char> t)
{
return std::get<i>(t);
}
int main()
{
std::tuple<char, char> t('H','i');
char c = get_elem_i<0>(t);
std::cout << "The char is: " << c << std::endl;
}
Now, I do not want to use a template which specifies the index (the exact reason why: I have templates that are deduced automatically, and I do not want to need to specify them all). So my first try was:
char get_elem_i(int i, std::tuple<char, char> t)
{
return std::get<i>(t);
}
I understand that this can not compile. Is there any way to assure the compiler that i
will be known at compile time? Maybe something like this?
char get_elem_i(compile_time_known int i, std::tuple<char, char> t)
Upvotes: 3
Views: 13194
Reputation: 10937
If you can know the value of i
at compile time then you can getting around specifying specifying the explicit value of i
by wrapping your logic for i
in aconstexpr
.
For example:
#include <tuple>
#include <iostream>
constexpr int compile_time_known_i(int input) { return input / 3; }
template<int i>
char get_elem_i(std::tuple<char, char> t)
{
return std::get<i>(t);
}
int main()
{
std::tuple<char, char> t('H','i');
char c = get_elem_i<0>(t);
char d = get_elem_i<compile_time_known_i(3)>(t);
std::cout << "The char is: " << c << " " << d << std::endl;
}
Given your i
's can be known at compile time, this may help clean things up (although how much sense this makes depends on your use case).
If it's the syntax of passing a parameter you are after, you could achieve this with the preprocessor - with some optional type_traits
safety.
#include <tuple>
#include <iostream>
#include <type_traits>
#define get_elem_i_ct(i, t) \
std::get<i>(t); \
static_assert(std::is_integral<decltype(i)>::value, #i " must be an integral type"); \
static_assert(std::is_same<decltype(t), std::tuple<char, char>>::value, #t " must be a tuple");
int main()
{
std::tuple<char, char> t('H','i');
char c = get_elem_i_ct(0, t)
char d = get_elem_i_ct(1, t)
std::cout << "The char is: " << c << " " << d << std::endl;
}
Although this achieves the stated syntactical requirement, I wouldn't recommend using this approach in anger - there's almost certainly a better solution to your actual problem.
Upvotes: 1
Reputation: 81926
You could use a std::array
instead of a std::tuple
. In the example given, the members of the tuple all have the same type.
So, we could do:
char get_elem_i(int i, std::array<char, 2> t)
{
return t[i];
}
Here's a slight variant on the example you gave to show why it's not directly possible in the general case:
???? get_elem_i(int i, std::tuple<char, struct foo, class bar> t) {
return std::get<i>(t);
}
What is the return type of that function? char
? struct foo
?
And you could always write a function like this:
char get_elem_i(int i, std::tuple<char, char> t) {
switch (i) {
case 0: return std::get<0>(t);
case 1: return std::get<1>(t);
}
assert(false);
}
Upvotes: 6