我想增加/減少 astd::variant的型別替代,基本上是這樣的:
using var_t = std::variant</*...*/>;
var_t var;
var.emplace< (var.index() 1) % std::variant_size<var_t> >(); // "increment" case, wrapping for good measure
這里的問題是,雖然emplace期望 clang 的錯誤訊息稱為“明確指定的引數”,index但似乎不是constexpr.
顯而易見的選擇是這樣的:
switch(var.index()){
0:
var.emplace<1>();
break;
1:
var.emplace<2>();
break;
// ...
variant_size<var_t>-1:
var.emplace<0>();
}
但這就是我個人所說的“非常丑陋”和“維護背后的巨大痛苦”(特別是因為我必須為遞增和遞減保持這些塊的兩個幾乎副本)。
有沒有更好/“正確”的方法來做到這一點?
如果這些資訊是在任何方面重要的是,我的定位目標C 20上clang有libstdc 。
uj5u.com熱心網友回復:
另一種可能的解決方案(在我看來)比@Jarod42 的解決方案更丑陋,并且依賴于在編譯時使用模板化 lambda 查找索引std::visit:
#include <variant>
template <class T, std::size_t I, class... Args>
struct index_of_;
template <class T, std::size_t I, class... Args>
struct index_of_<T, I, T, Args... >: std::integral_constant<std::size_t, I> {};
template <class T, std::size_t I, class U, class... Args>
struct index_of_<T, I, U, Args... >: index_of_<T, I 1, Args... > {};
template <class T, class... Args>
struct next_index: std::integral_constant<
std::size_t,
(index_of_<T, 0, Args... >::value 1) % sizeof... (Args)> {};
template <class... Args>
void increment(std::variant<Args...>& variant) {
// prior to C 20, you can use [&](auto const& arg) and retrieve T
// via std::decay_t<decltype(arg)>,
std::visit([&]<class T>(T const&) {
variant.template emplace<next_index<T, Args...>::value>();
}, variant);
}
與@Jarod42 解決方案不同,如果您的變體中有重復的型別,則此解決方案將不起作用。
uj5u.com熱心網友回復:
像往常一樣,std::index_sequence可能會有所幫助:
#include <variant>
template <typename... Ts, std::size_t... Is>
void next(std::variant<Ts...>& v, std::index_sequence<Is...>)
{
using Func = void (*)(std::variant<Ts...>&);
Func funcs[] = {
[](std::variant<Ts...>& v){ v.template emplace<(Is 1) % sizeof...(Is)>(); }...
};
funcs[v.index()](v);
}
template <typename... Ts>
void next(std::variant<Ts...>& v)
{
next(v, std::make_index_sequence<sizeof...(Ts)>());
}
演示
注:for prev,Is 1應替換為Is sizeof...(Is) - 1。
uj5u.com熱心網友回復:
這是需要基于索引的訪問的眾多情況之一。我們可以使用Boost.Mp11來撰寫:
template <typename F, typename Variant>
decltype(auto) visit_with_index(F&& f, Variant&& v) {
constexpr size_t N = mp_size<std::remove_cvref_t<Variant>>;
return mp_with_index<N>(v.index(), [&](auto I){
return f(I, std::get<I>(v));
});
}
這會將索引(它是一些整數常量)和元素傳遞給函式。現在我們可以寫:
template <typename... Args>
void next_alt(std::variant<Args...>& v) {
visit_with_index([&](auto I, auto&&){
v.emplace<(I 1) % sizeof...(Args)>();
}, v);
}
作為獎勵,mp_with_index是一個開關std::visit,因此它的性能比 好,所以無論如何它都是一個很好的解決方案。請注意,這不會處理valueless_by_exception,但如果需要,可以直接添加到頂部。
uj5u.com熱心網友回復:
這里的問題是,雖然
emplace期望 clang 的錯誤訊息稱為“明確指定的引數”,index但似乎不是constexpr.
您可以使用std::variant將運行時index轉換為編譯時常量,即std::integral_constant.
#include <variant>
#include <array>
template<std::size_t N>
using IC = std::integral_constant<std::size_t, N>;
template<std::size_t N>
constexpr auto gen_indices = []<std::size_t... Is>(
std::index_sequence<Is...>) {
return std::array{std::variant<IC<Is>...>(IC<Is>{})...};
}(std::make_index_sequence<N>{});
template <typename Variant>
constexpr void increment(Variant& v) {
constexpr auto size = std::variant_size_v<Variant>;
constexpr auto& indices = gen_indices<size>;
std::visit(
[&v](auto index) { v.template emplace<(index 1) % size>(); },
indices[v.index()]);
}
演示。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/331751.html
上一篇:從一個向量中選擇n個不同的元素,其概率與其索引成反比
下一篇:帶有模板方法id的模板類
