c++ - const 元组到 const 元组?

标签 c++ tuples variadic-templates

如果我有一个元组成员变量,其中元组中的类型是类模板的参数包,我可以使用静态成员函数将函数应用于元组中的每个对象,如下所示:

template<size_t I = 0, typename F, typename... Tp>
static void apply_to_foos(std::tuple<Tp...>& t, F func)  {
    auto& foo = std::get<I>(t);
    func(foo);
    if constexpr (I + 1 != sizeof...(Tp))
        apply_to_foos<I + 1>(t, func);
}

例如,如果 foos_是元组成员变量,我可以通过 foos 实现成员函数:

void frobnicate() {
   apply_to_foos( foos_, [](auto& f){f.frob();} );
}

等等。但是,如果 frobnicate一直是 const 我遇到了 foos_ 的问题现在将是 const,并且 apply_to_foos想要一个非常量元组。例如,这将不起作用(如果 foos 是某种容器)

size_t size() const {
   size_t sz = 0;
   apply_to_foos( foos_, [&sz](auto& f){ sz += f.size();} );
   return sz;
}

我可以实现 apply_to_foos 的重载这需要 const std::tuple<Tp...>& , const_cast 到一个非常量元组并调用原始重载,但是,好吧,那么我只是抛弃 const 性。

令人烦恼的是 apply_to_foos 的唯一部分关心常量的是签名。只要遵守常量性,其他所有内容都可以使用 const 值,例如lambda 需要引用 const 值等。如果我可以从 const 元组转换为 const 元组,那么我可以像这样实现 const 重载:

template<size_t I = 0, typename F, typename... Tp>
static void apply_to_foos(const std::tuple<Tp...>& t, F func)  {
    auto& tup_of_consts = const_tuple_to_tuple_of_consts(t);
    apply_to_foos(tup_of_consts, func);
}

size()成员函数会自然地工作......我觉得必须有一种更简单的方法来处理这个问题?

最佳答案

您无法转换 const std::tuple<T1, T2>std::tuple<const T1, const T2>无需复制所含元素。

您有两种选择:

1。推导出 t 的类型并完全回避问题:

template<size_t I = 0, typename F, typename T>
static void apply_to_foos(T& t, F func)  {
    auto& foo = std::get<I>(t);
    func(foo);
    if constexpr (I + 1 != std::tuple_size<T>::value)
        apply_to_foos<I + 1>(t, func);
}

Live Demo

类型为t推断,这两种情况都会起作用。如果通过了const元组然后 T将被推导为 const std::tuple<...>制作 t 的类型const std::tuple<...>&如果通过了非 const元组然后 T将被推导为std::tuple<...>t 的类型将是std::tuple<...>& 。唯一需要的其他更改是使用 std::tuple_size<T>::value代替sizeof...(Tp) 。请注意,这也允许 apply_to_foos与其他类型一起使用,例如 std::arraystd::pair .

您可能还想应用完美转发以允许 apply_to_foos使用右值并保留元组元素的值类别。例如:

template<size_t I = 0, typename F, typename T>
static void apply_to_foos(T&& t, F func)  {
    func(std::get<I>(std::forward<T>(t)));
    if constexpr (I + 1 != std::tuple_size<std::remove_reference_t<T>>::value)
        apply_to_foos<I + 1>(std::forward<T>(t), func);
}

Live Demo

2。创建一个包含对原始元组内容的引用的新元组

创建 apply_to_foos 的第二个重载接受对 const 的引用元组并创建一个临时元组 const对原始元组元素的引用:

template<typename F, typename... Tp>
static void apply_to_foos(const std::tuple<Tp...>& t, F func) {
    std::tuple<std::add_const_t<Tp>&...> tuple_of_const = t;
    apply_to_foos(tuple_of_const, func);
}

Live Demo

这可以正常工作,但它在值类别保存方面存在问题。元组右值的元素将作为 const 传递给回调函数。例如,左值不能轻易移动。

关于c++ - const 元组到 const 元组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66002324/

相关文章:

python - 带元组键的字典 : All tuples with the same first element

python - 遍历元组并计算数字的百分比

c++ - 模板类的多个可变参数包

c++ - 检测是否存在具有给定签名的函数

c++ - 使用内置的 C++ 结构

c++ - 如何使用 `std::function` 作为函数参数创建可变参数模板函数?

c++ - QTreeWidget : Windows Explorer-like editing

c++ - 模型更新时 QML ListView 默认行为

c++ - CMake:如何清除目标编译选项

c++ - 如何从引用中获取指针?