Bar*_*gor 11 c++ c++-standard-library c++17
是否有标准库的实用程序,以获得指标给定的类型的std::variant?或者我应该为自己制作一个?也就是说,我想获得Bin 的索引std::variant<A, B, C>并获得该返回1.
有std::variant_alternative相反的操作.当然,std::variant列表上可能有很多相同的类型,所以这个操作不是双射,但对我来说这不是问题(我可以首先出现列表中的类型,或列表上的唯一类型std::variant).
Bar*_*gor 12
我为元组找到了这个答案并稍微修改了它:
template<typename VariantType, typename T, std::size_t index = 0>
constexpr std::size_t variant_index() {
if constexpr (index == std::variant_size_v<VariantType>) {
return index;
} else if constexpr (std::is_same_v<std::variant_alternative_t<index, VariantType>, T>) {
return index;
} else {
return variant_index<VariantType, T, index + 1>();
}
}
Run Code Online (Sandbox Code Playgroud)
它对我有用,但现在我很好奇如何在没有 constexpr if 的情况下以旧方式做到这一点,作为一个结构。
Bar*_*rry 12
我们可以利用index()几乎已经做到正确的事实.
我们不能随意创建各种类型的实例 - 我们不知道如何去做,任意类型可能不是文字类型.但是我们可以创建我们知道的特定类型的实例:
template <typename> struct tag { }; // <== this one IS literal
template <typename T, typename V>
struct get_index;
template <typename T, typename... Ts>
struct get_index<T, std::variant<Ts...>>
: std::integral_constant<size_t, std::variant<tag<Ts>...>(tag<T>()).index()>
{ };
Run Code Online (Sandbox Code Playgroud)
也就是说,要找到的索引B中variant<A, B, C>我们构建了一个variant<tag<A>, tag<B>, tag<C>>具有tag<B>和找到自己的指数.
这仅适用于不同类型.
您还可以使用折叠表达式来执行此操作:
template <typename T, typename... Ts>
constexpr size_t get_index(std::variant<Ts...> const&) {
size_t r = 0;
auto test = [&](bool b){
if (!b) ++r;
return b;
};
(test(std::is_same_v<T,Ts>) || ...);
return r;
}
Run Code Online (Sandbox Code Playgroud)
当我们第一次匹配类型时,折叠表达式就会停止,此时我们将停止递增r。即使对于重复的类型,这也适用。如果未找到类型,则返回大小。return如果需要的话,在这种情况下可以很容易地将其更改为“不” ,因为函数return中的缺失constexpr是格式错误的。
如果您不想获取 的实例variant,则此处的参数可以是 a tag<variant<Ts...>>。
对于 Boost.Mp11,这是一个简短的一行:
template<typename Variant, typename T>
constexpr size_t IndexInVariant = mp_find<Variant, T>::value;
Run Code Online (Sandbox Code Playgroud)
完整示例:
#include <variant>
#include <boost/mp11/algorithm.hpp>
using namespace boost::mp11;
template<typename Variant, typename T>
constexpr size_t IndexInVariant = mp_find<Variant, T>::value;
int main()
{
using V = std::variant<int,double, char, double>;
static_assert(IndexInVariant<V, int> == 0);
// for duplicates first idx is returned
static_assert(IndexInVariant<V, double> == 1);
static_assert(IndexInVariant<V, char> == 2);
// not found returns ".end()"/ or size of variant
static_assert(IndexInVariant<V, float> == 4);
// beware that const and volatile and ref are not stripped
static_assert(IndexInVariant<V, int&> == 4);
static_assert(IndexInVariant<V, const int> == 4);
static_assert(IndexInVariant<V, volatile int> == 4);
}
Run Code Online (Sandbox Code Playgroud)