c++ - 具有两个(或更多)特定包(专业化/重载)的可变参数函数模板
问题描述
函数 'Process' 采用可变数量的变量类型参数。为了处理不同的情况,我成功地重载了它,如下所示:
// general case
template <typename ...Types>
void Process( const Types&... items )
// single T
template <typename T>
void Process( const T& t )
// one or more of type NVP<>
template <typename T1, typename ...Types>
void Process( const NVP<T1>& nvp1, const NVP<Types>&... nvps )
我想要做 - 但不能 - 是以下内容ATT<>
:对于具有任意数量的类型的前导参数后跟任意数量的NVP<>
类似这样的情况,我需要重载:
// any number of leading Types ATT<> followed by any number of NVP<>
template <typename ...ATypes, typename ...BTypes>
void Process( const ATT<ATypes>&... atts, const NVP<BTypes>&... nvps )
起初你会认为编译器匹配这个应该是“容易的”,如果它已经可以做其他情况的话。这里绝对没有歧义!?但是,匹配失败,没有错误消息,但是编译器忽略了所需的重载。
当前使用带有 /std:c++17 的 VS2017
笔记:
1.显然,可以为这样的一种领先类型完成ATT<T1>
// one leading Type ATT<T1>
template <typename T1, typename ...Types>
void Process( const ATT<T1>& a1, const Types&... remaining )
但不止一个,我需要做一些丑陋的手动递归。我真的很想拥有整个领导ATT<...>
。
2.我知道一个领先的参数包——一般类型的——对于匹配总是模棱两可的,但是对于像ATT<ATypes>...
没有模棱两可的专业化来说不应该存在。
解决方案
const Types&...
您可以根据 ifTypes...
匹配从重载中分派ATT<T>..., NVP<U>...
。
这里的基本策略是找到 last 的索引ATT<T>
,将所有内容作为一个元组转发,然后使用适当的索引序列进行索引以转发到另一个函数,其中ATT
值和NVP
值在两个元组中:
namespace detail {
template<class...>
struct get_split_index;
template<class T, class... Others>
struct get_split_index<T, Others...> {
static constexpr std::size_t i = -1;
};
template<class T, class... Others>
struct get_split_index<ATT<T>, Others...> {
static constexpr std::size_t next = get_split_index<Others...>::i;
static constexpr std::size_t i = next == -1 ? -1 : next + 1u;
};
template<class T, class... Others>
struct get_split_index<NVP<T>, Others...> {
// will be 0 if the rest are all NVP<T>, otherwise -1
static constexpr std::size_t i = get_split_index<Others...>::i;
};
template<>
struct get_split_index<> {
static constexpr std::size_t i = 0;
};
template<typename... ATypes, typename... BTypes, std::size_t... ATT_I, std::size_t... NVP_I>
void Process(const std::tuple<const ATT<ATypes>&...>& att, const std::tuple<const NVP<BTypes>&...>& nvp, std::index_sequence<ATT_I...>, std::index_sequence<NVP_I...>) {
// Use (std::get<ATT_I>(att)) and (std::get<NVP_I>(nvp))
// instead of (atts) and (nvps) that you would use in your
// supposed `void Process(const ATT<ATypes>&..., const NVP<BTypes>&...)`
}
template<typename... Types, std::size_t... ATT_I, std::size_t... NVP_I>
void ProcessDispatch(const std::tuple<Types...>& t, std::index_sequence<ATT_I...> att_i, std::index_sequence<NVP_I...> nvp_i) {
detail::Process(std::forward_as_tuple(std::get<ATT_I>(t)...), std::forward_as_tuple(std::get<NVP_I + sizeof...(ATT_I)>(t)...), att_i, nvp_i);
}
}
template <typename ...Types>
void Process( const Types&... items ) {
constexpr std::size_t split_index = detail::get_split_index<Types...>::i;
if constexpr (split_index != -1) {
// Might want to check `&& sizeof...(Types) != 0`
detail::ProcessDispatch(std::forward_as_tuple(items...), std::make_index_sequence<split_index>{}, std::make_index_sequence<sizeof...(Types) - split_index>{});
} else {
// general case
}
}
template <typename T>
void Process( const T& t ) {
// single T
}
template <typename T1, typename ...Types>
void Process( const NVP<T1>& nvp1, const NVP<Types>&... nvps ) {
// one or more of type NVP<>
// This can also be folded into `detail::Process`, checking
// `if constexpr (sizeof...(BTypes) == 0)`.
}
推荐阅读
- graphviz - Graphviz/自定义边缘对齐
- javascript - 如何使用车把更改 json 中的字体颜色负数、正数数据?
- mysql - 同一张表中(不是和是)的Mysql WHERE条件
- android - 我想创建一个颤动页面来加载和播放存储在 Firebase 存储中的视频
- background - 后台奇怪的 JFrog Artifactory 进程(Ubuntu 18.04)
- android - Flutter:未来的构建
- c# - 我无法使用多个按钮将子项添加到 ListView
- ios - 使用 fastlane 远程构建 ios 应用程序时出错
- javascript - 如何使用 Bootstrap 设置父 div 的表格高度
- tensorflow - 有没有办法在 TensorFlow 中选择学习率和预热学习率(没有 Keras 的 API)?