c++ - 为什么在分解 std::tuple 时需要 std::integral_constant?

标签 c++ c++17 variadic-templates template-meta-programming generic-lambda

#include <iostream>

#include <tuple>
#include <iostream>
#include <utility>

template <std::size_t... Idx>
auto make_index_dispatcher(std::index_sequence<Idx...>) 
{
    return [](auto&& f) { (f(std::integral_constant<std::size_t, Idx>{}), ...); };
}

template <std::size_t N>
auto make_index_dispatcher() 
{
    return make_index_dispatcher(std::make_index_sequence<N>{});
}

template <typename Tuple, typename Func>
void for_each(Tuple&& t, Func&& f) 
{
    constexpr auto n = std::tuple_size<std::decay_t<Tuple>>::value;
    auto dispatcher = make_index_dispatcher<n>();
    dispatcher([&f, &t](auto idx) { f(std::get<idx>(std::forward<Tuple>(t))); });
}

int main() 
{
    for_each(std::make_tuple(1, 42.1, "hi"), [](auto&& e) {std::cout << e << ","; });
}

问题 1> 为什么我必须使用 std::integral_constant<std::size_t, Idx>{}而不是简单的 Idx在以下声明中?据我了解,std::integral_constant<std::size_t, Idx>是一种类型。 std::integral_constant<std::size_t, Idx>{} 是真的吗是 Idx 的值?

//确定

template <std::size_t... Idx>
auto make_index_dispatcher(std::index_sequence<Idx...>) 
{
    return [](auto&& f) { (f(std::integral_constant<std::size_t, Idx>{}), ...); };
}

//错误

template <std::size_t... Idx>
auto make_index_dispatcher(std::index_sequence<Idx...>) 
{
    return [](auto&& f) { (f(Idx), ...); };
}

std::get 是真的吗?预期的编译时常量表达式 while Idx不是编译时常量表达式吗?

问题2> 为什么我们不能通过std::index_sequence通过引用?

//错误: auto make_index_dispatcher(std::index_sequence<Idx...>&)

谢谢

最佳答案

Why I have to use std::integral_constant{} instead of simply Idx in the following statement?

因为函数参数永远不是常量表达式。您可以简单地将索引作为非类型模板参数传递,它们是常量表达式。这对于 C++20 模板 lambda 尤其适用:

template <std::size_t... Idx>
auto make_index_dispatcher(std::index_sequence<Idx...>) 
{
    return [](auto&& f) { (f.template operator()<Idx>(), ...); };
}

template <typename Tuple, typename Func>
void for_each(Tuple&& t, Func&& f) 
{
    constexpr auto n = std::tuple_size<std::decay_t<Tuple>>::value;
    auto dispatcher = make_index_dispatcher<n>();
    dispatcher([&f, &t]<auto Idx>(){ f(std::get<Idx>(std::forward<Tuple>(t))); });
}

live example on godbolt.org


Why we cannot pass std::index_sequence by reference?

可以,但是您需要像使用任何其他非 const 引用一样使用左值调用您的函数。这编译:

template <std::size_t... Idx>
auto make_index_dispatcher(std::index_sequence<Idx...>&) 
{
}

int main()
{
    std::index_sequence<> is;        
    make_index_dispatcher(is);
}

此外,它完全没用。


此外,您的整个代码可以简单地是:

int main() 
{
    std::apply([](auto&&... xs)
    {
        ((std::cout << xs << ','), ...);
    }, std::make_tuple(1, 42.1, "hi"));
}

关于c++ - 为什么在分解 std::tuple 时需要 std::integral_constant?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57397058/

相关文章:

c++ - samplerCube 数组

c++ - 在什么条件下使用 std::memcpy 在对象之间进行复制是安全的?

C++ 将包含数字和单词的文本文件列表转换为整数二维数组

c++单链表(使用结构),插入有问题

c++ - 具有空参数包的递归可变参数模板(以避免基本情况的重复)

c++ - 将 C++ 类型信息保存到文件中以供跨程序调用使用

c++ - "there is no smaller array object that satisfies these constraints"是什么意思?

c++ - 为什么在 C++17 中添加了 std::reduce?

C++:将 Args && ... _args 传递给嵌套列表的正确方法?

c++ - std::array的演绎指南