I would like to access to a tuple element at compile time by a value constexpr in the type
#include <iostream>
#include <tuple>
#include <utility>
struct A {
static constexpr int id = 1;
void work() {
std::cout << "A" << std::endl;
}
};
struct B {
static constexpr int id = 2;
void work() {
std::cout << "B" << std::endl;
}
};
int main() {
A a;
B b;
std::tuple<A,B> t = std::make_tuple(a,b);
static constexpr int search_id = 2;
auto& item = std::get< ? ( T::id == search_id ) ? >(t);
item.work();
return 0;
}
I guess using std::apply
and test would be a runtime search...
I'm using c 20
CodePudding user response:
Instead of std::get
a single element, you can use std::apply
to iterate over the elements of the tuple and perform operations based on the element type
A a;
B b;
auto t = std::make_tuple(a, b);
static constexpr int search_id = 2;
std::apply([](auto&... items) {
([]<class T>(T& item) {
if constexpr (T::id == search_id)
item.work();
}(items), ...);
}, t);
If you really want to get a single tuple element with a specific id
value, you can still use std::apply
to expand the id
of all elements and find the offset of the value equal to search_id
as the template parameter of std::get
auto& item = std::apply([&t]<class... Args>(const Args&... items) -> auto& {
constexpr auto id = [] {
std::array ids{Args::id...};
return ids.end() - std::ranges::find(ids, search_id);
}();
return std::get<id>(t);
}, t);
item.work();
CodePudding user response:
You can create constrexpr
function to get index:
template <typename... Ts>
constexpr std::size_t get_index(int id)
{
constexpr int ids[] = {Ts::id...};
const auto it = std::find(std::begin(ids), std::end(ids), id);
// Handle absent id.
if (it == std::end(ids)) {
throw std::runtime("Invalid id");
}
// You can also possibly handle duplicate ids.
return std::distance(std::begin(ids), it);
}
template <int id, typename... Ts>
constexpr auto& get_item(std::tuple<Ts...>& t)
{
return std::get<get_index<Ts...>(id)>(t);
}
template <int id, typename... Ts>
constexpr const auto& get_item(const std::tuple<Ts...>& t)
{
return std::get<get_index<Ts...>(id)>(t);
}
and then
auto& item = get_item<search_id>(t);
CodePudding user response:
I'm confused by this line:
static constexpr int search_id = 2;
What is purpose of it?
Note that using a type alias solves problem in clean way and you can still get id
value:
int main() {
A a;
B b;
std::tuple<A,B> t = std::make_tuple(a,b);
using search = B;
auto& item = std::get<search>(t);
item.work();
std::cout << search::id << '\n';
return 0;
}
https://godbolt.org/z/se5jxMWdv
Note also that code is more maintainable, no magic value 2
.