如何编写适用于映射和对向量的 C++ 模板>
How to write a c++ template that works for both a map and vector of pair>
我想编写一个模板函数,它遍历 std::pair
的容器,return 是一个模板化值,这两种类型都是一对。我已经让这个为 std::map
工作,如下所示:
template <typename T1, typename T2>
std::pair<std::vector<T1>, std::vector<T2>> unzip(const std::map<T1,T2>& zipped)
{
auto unzipped = std::make_pair(std::vector<T1>(), std::vector<T2>());
for (auto& one_two : zipped)
{
unzipped.first.push_back(one_two.first);
unzipped.second.push_back(one_two.second);
}
return unzipped;
}
这很好用,但它将容器限制为 std::map
。我想要完成的是让它也适用于 std::vector<std::pair<T1,T2>>
之类的东西,因为对两个容器的迭代工作方式相同。
我尝试通过更改模板参数使容器成为模板:
template <typename T1, typename T2, template<typename ... Types> class Container>
std::pair<std::vector<T1>, std::vector<T2>> unzip(const Container<T1,T2>& zipped)
{
//do stuff and return
}
但在这种情况下,如果不使用 std::map
推导失败,因为 std::vector
仅依赖于单一类型。然后我尝试变得更有创意,但编译器抱怨得更多:
template <typename PairContainerType>
std::pair<std::vector<typename PairContainerType::value_type::first_type>,
std::vector<typename PairContainerType::value_type::second_type>>
unzip(const PairContainerType& zipped)
{
typedef typename PairContainerType::value_type::first_type T1;
typedef typename PairContainerType::value_type::second_type T2;
//do the same stuff and return
}
我认为我正在尝试做的事情应该是可能的,但我很茫然。如果这很重要,我正在使用 c++11
,但如果我想要的东西在未来的版本中可用,我仍然对这些解决方案感兴趣。谢谢。
更新:
多亏了 RiaD,我使用 c++11 得到了以下结果:
template <typename PairContainerType,
typename T1 = typename std::remove_const<typename PairContainerType::value_type::first_type>::type,
typename T2 = typename std::remove_const<typename PairContainerType::value_type::second_type>::type>
std::pair<std::vector<T1>, std::vector<T2>> unzip(const PairContainerType& zipped)
{
//do stuff and return
}
请注意,它与接受的答案略有不同,因为它使用 std::remove_const
而不是 std::remove_const_t
并且需要在末尾添加 ::type
。
RiaD 还指出模板类型 T1
和 T2
可以被调用者覆盖。正如 Jarod42 所建议的,这可以通过一些额外的输入来缓解,这让我进入了最终的 c++11 解决方案:
template <typename PairContainerType>
std::pair<std::vector<typename std::remove_const<typename PairContainerType::value_type::first_type>::type>,
std::vector<typename std::remove_const<typename PairContainerType::value_type::second_type>::type>>
unzip(const PairContainerType& zipped)
{
auto unzipped = std::make_pair(
std::vector<typename std::remove_const<typename PairContainerType::value_type::first_type>::type>(),
std::vector<typename std::remove_const<typename PairContainerType::value_type::second_type>::type>());
for (const auto& one_two : zipped)
{
unzipped.first.push_back(one_two.first);
unzipped.second.push_back(one_two.second);
}
return unzipped;
}
总的来说,c++14 和 c++17 看起来很有吸引力。我本可以使用 auto
return 功能节省自己的时间!
template<class T>
struct zipper {
using first_t = remove_cv_t<typename T::value_type::first_type>;
using second_t = typename T::value_type::second_type;
template <class container>
static std::pair<std::vector<first_t>, std::vector<second_t>> unzip(const container& zipped)
{
auto unzipped = std::make_pair(std::vector<first_t>(), std::vector<second_t>());
for (auto& one_two : zipped)
{
unzipped.first.emplace_back(one_two.first);
unzipped.second.emplace_back(one_two.second);
}
return unzipped;
}
};
template<class container>
auto unzip(const container& cont) {
return zipper<container>::unzip(cont);
}
通常使用 c++ 你只允许任何类型,如果它不正确就让它失败。要获得 T1 和 T2,您可能会获得 value_type 个集合(存在于 std::map
和 std::vector<std::pair<>>
以及其他集合中,例如 std::set<std::pair<>>
)
template <typename T, typename T1 = std::remove_const_t<typename T::value_type::first_type>, typename T2 = std::remove_const_t<typename T ::value_type::second_type>>
std::pair<std::vector<T1>, std::vector<T2>> unzip(const T& zipped)
{
auto unzipped = std::make_pair(std::vector<T1>(), std::vector<T2>());
for (auto& one_two : zipped)
{
unzipped.first.push_back(one_two.first);
unzipped.second.push_back(one_two.second);
}
return unzipped;
}
它有(轻微的)缺点,即有人可能会在适合时强制使用 T1 和 T2。您可以将它们从模板参数列表中删除。
template <typename T>
auto /* or return type (but it will require copy-pasting) before c++14*/
unzip(const T& zipped)
{
using T1 = std::remove_const_t<typename T::value_type::first_type>; //may need to remove const
using T2 = std::remove_const_t<typename T::value_type::second_type>;
// impl
}
需要删除 const,因为 std::map
的 value_type 是 std::pair<const K, V>
。如果您需要较旧的标准支持,则可以在没有 std::remove_const_t
的情况下完成,例如对于 C++11,你需要 typename std::remove_const<>::type
我想编写一个模板函数,它遍历 std::pair
的容器,return 是一个模板化值,这两种类型都是一对。我已经让这个为 std::map
工作,如下所示:
template <typename T1, typename T2>
std::pair<std::vector<T1>, std::vector<T2>> unzip(const std::map<T1,T2>& zipped)
{
auto unzipped = std::make_pair(std::vector<T1>(), std::vector<T2>());
for (auto& one_two : zipped)
{
unzipped.first.push_back(one_two.first);
unzipped.second.push_back(one_two.second);
}
return unzipped;
}
这很好用,但它将容器限制为 std::map
。我想要完成的是让它也适用于 std::vector<std::pair<T1,T2>>
之类的东西,因为对两个容器的迭代工作方式相同。
我尝试通过更改模板参数使容器成为模板:
template <typename T1, typename T2, template<typename ... Types> class Container>
std::pair<std::vector<T1>, std::vector<T2>> unzip(const Container<T1,T2>& zipped)
{
//do stuff and return
}
但在这种情况下,如果不使用 std::map
推导失败,因为 std::vector
仅依赖于单一类型。然后我尝试变得更有创意,但编译器抱怨得更多:
template <typename PairContainerType>
std::pair<std::vector<typename PairContainerType::value_type::first_type>,
std::vector<typename PairContainerType::value_type::second_type>>
unzip(const PairContainerType& zipped)
{
typedef typename PairContainerType::value_type::first_type T1;
typedef typename PairContainerType::value_type::second_type T2;
//do the same stuff and return
}
我认为我正在尝试做的事情应该是可能的,但我很茫然。如果这很重要,我正在使用 c++11
,但如果我想要的东西在未来的版本中可用,我仍然对这些解决方案感兴趣。谢谢。
更新: 多亏了 RiaD,我使用 c++11 得到了以下结果:
template <typename PairContainerType,
typename T1 = typename std::remove_const<typename PairContainerType::value_type::first_type>::type,
typename T2 = typename std::remove_const<typename PairContainerType::value_type::second_type>::type>
std::pair<std::vector<T1>, std::vector<T2>> unzip(const PairContainerType& zipped)
{
//do stuff and return
}
请注意,它与接受的答案略有不同,因为它使用 std::remove_const
而不是 std::remove_const_t
并且需要在末尾添加 ::type
。
RiaD 还指出模板类型 T1
和 T2
可以被调用者覆盖。正如 Jarod42 所建议的,这可以通过一些额外的输入来缓解,这让我进入了最终的 c++11 解决方案:
template <typename PairContainerType>
std::pair<std::vector<typename std::remove_const<typename PairContainerType::value_type::first_type>::type>,
std::vector<typename std::remove_const<typename PairContainerType::value_type::second_type>::type>>
unzip(const PairContainerType& zipped)
{
auto unzipped = std::make_pair(
std::vector<typename std::remove_const<typename PairContainerType::value_type::first_type>::type>(),
std::vector<typename std::remove_const<typename PairContainerType::value_type::second_type>::type>());
for (const auto& one_two : zipped)
{
unzipped.first.push_back(one_two.first);
unzipped.second.push_back(one_two.second);
}
return unzipped;
}
总的来说,c++14 和 c++17 看起来很有吸引力。我本可以使用 auto
return 功能节省自己的时间!
template<class T>
struct zipper {
using first_t = remove_cv_t<typename T::value_type::first_type>;
using second_t = typename T::value_type::second_type;
template <class container>
static std::pair<std::vector<first_t>, std::vector<second_t>> unzip(const container& zipped)
{
auto unzipped = std::make_pair(std::vector<first_t>(), std::vector<second_t>());
for (auto& one_two : zipped)
{
unzipped.first.emplace_back(one_two.first);
unzipped.second.emplace_back(one_two.second);
}
return unzipped;
}
};
template<class container>
auto unzip(const container& cont) {
return zipper<container>::unzip(cont);
}
通常使用 c++ 你只允许任何类型,如果它不正确就让它失败。要获得 T1 和 T2,您可能会获得 value_type 个集合(存在于 std::map
和 std::vector<std::pair<>>
以及其他集合中,例如 std::set<std::pair<>>
)
template <typename T, typename T1 = std::remove_const_t<typename T::value_type::first_type>, typename T2 = std::remove_const_t<typename T ::value_type::second_type>>
std::pair<std::vector<T1>, std::vector<T2>> unzip(const T& zipped)
{
auto unzipped = std::make_pair(std::vector<T1>(), std::vector<T2>());
for (auto& one_two : zipped)
{
unzipped.first.push_back(one_two.first);
unzipped.second.push_back(one_two.second);
}
return unzipped;
}
它有(轻微的)缺点,即有人可能会在适合时强制使用 T1 和 T2。您可以将它们从模板参数列表中删除。
template <typename T>
auto /* or return type (but it will require copy-pasting) before c++14*/
unzip(const T& zipped)
{
using T1 = std::remove_const_t<typename T::value_type::first_type>; //may need to remove const
using T2 = std::remove_const_t<typename T::value_type::second_type>;
// impl
}
需要删除 const,因为 std::map
的 value_type 是 std::pair<const K, V>
。如果您需要较旧的标准支持,则可以在没有 std::remove_const_t
的情况下完成,例如对于 C++11,你需要 typename std::remove_const<>::type