首页 > 解决方案 > 获取满足特征的 std::tuple 的第一个元素

问题描述

我正在使用 C++17。我想获得满足某种类型特征的元组元素。如果可以通用地提供特征,那将是惊人的,但我会对某个特征的特定功能感到满意。用法可能如下所示:

auto my_tuple = std::make_tuple { 0.f, 1 };

auto basic = get_if_integral (my_tuple);
auto fancy = get_if<std::is_floating_point> (my_tuple);

std::cout << basic; // '1'
std::cout << fancy; // '0.f'

理想情况下,如果多个元素满足该特征,则编译将失败,例如std::get (std::tuple).

标签: c++c++17variadic-templatestemplate-meta-programmingstdtuple

解决方案


这是一种不使用递归的非常简单的方法:

template <template <typename...> typename T, typename... Ts>
constexpr int index_of_integral(const T<Ts...>&)
{
    const bool a[] = { std::is_integral_v<Ts>... };
    for (int i = 0; i < sizeof...(Ts); ++i) if (a[i]) return i;
    return -1;
}

template <typename T>
constexpr decltype(auto) get_if_integral(T&& t)
{
    return std::get<index_of_integral(t)>(std::forward<T>(t));
}

int main()
{
    constexpr auto t = std::make_tuple(3.14, 42, "xyzzy");
    static_assert(get_if_integral(t) == 42);
}

它可以很容易地扩展到对特征进行参数化。

使它成为 C++17 的唯一因素是is_integral_v变量 template 和 single-argument static_assert。其他一切都是 C++14。

请注意,在 C++20 中,for循环可以替换为std::findand std::distance

理想情况下,它应该抛出异常而不是返回-1,但编译器似乎不喜欢这样。

受到这个答案的启发。


推荐阅读