Следующий минимальный пример компилируется с 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;
}
Теперь я не хочу использовать шаблон, который определяет индекс (точная причина, почему: у меня есть шаблоны, которые выводятся автоматически, и я не хочу указывать их все). Итак, моя первая попытка была:
char get_elem_i(int i, std::tuple<char, char> t)
{
return std::get<i>(t);
}
Я понимаю, что это не может скомпилировать. Есть ли способ заверить компилятор, что i
будет известно во время компиляции? Может как то так?
char get_elem_i(compile_time_known int i, std::tuple<char, char> t)
Вы могли бы использовать std::array
вместо std::tuple
, В приведенном примере члены кортежа имеют одинаковый тип.
Итак, мы могли бы сделать:
char get_elem_i(int i, std::array<char, 2> t)
{
return t[i];
}
Вот небольшой вариант примера, который вы привели, чтобы показать, почему это невозможно напрямую в общем случае:
???? get_elem_i(int i, std::tuple<char, struct foo, class bar> t) {
return std::get<i>(t);
}
Каков тип возврата этой функции? char
? struct foo
?
И вы всегда можете написать такую функцию:
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);
}
Если вы можете знать значение i
во время компиляции, то вы можете обойти, указав явное значение i
оборачивая вашу логику для i
вconstexpr
,
Например:
#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;
}
Учитывая ваш i
Это может быть известно во время компиляции, это может помочь очистить вещи (хотя насколько это имеет смысл, зависит от вашего варианта использования).
Если это синтаксис передачи нужного вам параметра, вы можете добиться этого с помощью препроцессора — с некоторыми дополнительными type_traits
безопасность.
#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;
}
Хотя это соответствует заявленным синтаксическим требованиям, я не рекомендовал бы использовать этот подход в гневе — почти наверняка есть лучшее решение вашей реальной проблемы.