c++ - const 元组到 const 元组?
问题描述
如果我有一个元组成员变量,其中元组中的类型是类模板的参数包,我可以使用如下静态成员函数将函数应用于元组中的每个对象:
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-ness。
令人讨厌的是,唯一apply_to_foos
关心 const-ness 的部分是签名。只要遵守 const-ness,其他所有东西都可以使用 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);
}
使用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::array
和std::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);
}
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);
}
这可以正常工作,但它在价值类别保存方面存在问题。例如,元组右值的元素将作为左值传递给回调函数,const
并且不能轻易移动。
推荐阅读
- c++ - 我无法在不同的线程(C++)中使用 WindowsForms 方法
- android - 如何将音频文件保存到外部存储?
- excel - 用于在 Excel 中更改边框线颜色的 VBA
- c++ - C++ 中基类和派生类对象的树结构
- python - 在上一段的空格后输入文本数据
- prometheus - 为非原因的微服务静音警报
- javascript - 如何在Javascript中获取全局对象的名称和道具
- firebase - 托管中自定义域上的 Firebase 动态链接重写但如何
- javascript - 如何在单击超链接时以弹出模式打开另一个页面
- nuget - Nuget 包管理器已损坏 - '' 不是 VS2019“管理解决方案包”中的有效版本字符串