从函数模板参数自动推断对容器的元素类型
Automatically deducing element type of pair container from the function template argument
我想编写一个模板函数,它接受一个键值对容器(例如 map<K,V>
或 vector<pair<K,V>>
)和 returns 一个键容器容器。例如:
template<typename C, typename K, typename V>
vector<vector<K>> partition_keys(const C& input)
{
vector<vector<K>> result;
...
// do something
for (const auto &pair : input)
{
cout << pair.first << "," << pair.second << std::endl;
}
...
return result;
}
我想这样称呼它:
// map
map<string, string> product_categories;
partition_keys(product_categories); // doesn't work
partition_keys<map<string, string>, string, string>(product_categories); // have to do this
// vector
vector<pair<string, string>> movie_genres;
partition_keys(movie_genres); // doesn't work
partition_keys<vector<pair<string, string>>, string, string>(movie_genres); // have to do this
但是,如果不显式指定,编译器无法推导出模板参数 K 和 V。我希望该函数适用于具有任何类型对的任何容器;所以我想避免为 map<K,V>
、list<pair<K,V>>
、vector<pair<K,V>>
等编写单独的模板函数
因此,我不得不按如下方式修改模板函数签名,以使其按我想要的方式工作:
template<typename C,
typename K = remove_const_t<C::value_type::first_type>,
typename V = C::value_type::second_type>
vector<vector<K>> partition_keys(const C& input);
有更好的方法吗?根据 C
的 value_type
推导 K
和 V
的类型是一个好习惯吗?此外,调用者有可能为 K
和 V
.
显式传递无效参数
还要注意我是如何通过调用 remove_const_t
来删除键类型的常量的,因为对于 map
,C::value_type::first_type
是 const
类型而标准不是允许创建 const
类型的集合。
很好。如果你不喜欢模板参数中的混乱,你可以将键类型直接放在 return 类型中,可能是尾随形式:
template <typename C>
auto partition_keys(const C& input)
-> vector<vector<remove_const_t<typename C::value_type::first_type>>>;
或者依靠 return 类型推导来实现正常功能并完全省略 return 类型:
template <typename C>
auto partition_keys(const C& input)
{
vector<vector<remove_const_t<typename C::value_type::first_type>>> result;
//...
return result;
}
你做的是对的,更具体地说:
template<typename C,
typename Pair = typename C::value_type,
typename Key = std::remove_const_t<typename Pair::first_type>,
typename Value = typename Pair::first_type
>
vector<vector<Key>> partition_keys(const C& input)
是正确的(Demo)。但是,如果您需要对不同的模板函数使用类似的类型分解,例如:
....repeat above templated type decomposition....
vector<vector<Key>> sorted_keys(const C& input);
....repeat above templated type decomposition....
vector<vector<Key>> filtered_keys(const C& input);
可能打字太多了。在这种情况下,您可以创建一个简单的特征 class 来帮助您。
template<typename T>
struct PTraits{
using pair_type = typename T::value_type;
using key_type = std::remove_const_t<typename pair_type::first_type>;
using value_type = typename pair_type::second_type;
};
template<typename T>
using KeyTypper = typename PTraits<T>::key_type;
然后用作...
template<typename C, typename Key = KeyTypper<C>>
vector<vector<Key>> partition_keys(const C& input);
template<typename C, typename Key = KeyTypper<C>>
vector<vector<Key>> sorted_keys(const C& input);
template<typename C, typename Key = KeyTypper<C>>
vector<vector<Key>> filtered_keys(const C& input);
我想编写一个模板函数,它接受一个键值对容器(例如 map<K,V>
或 vector<pair<K,V>>
)和 returns 一个键容器容器。例如:
template<typename C, typename K, typename V>
vector<vector<K>> partition_keys(const C& input)
{
vector<vector<K>> result;
...
// do something
for (const auto &pair : input)
{
cout << pair.first << "," << pair.second << std::endl;
}
...
return result;
}
我想这样称呼它:
// map
map<string, string> product_categories;
partition_keys(product_categories); // doesn't work
partition_keys<map<string, string>, string, string>(product_categories); // have to do this
// vector
vector<pair<string, string>> movie_genres;
partition_keys(movie_genres); // doesn't work
partition_keys<vector<pair<string, string>>, string, string>(movie_genres); // have to do this
但是,如果不显式指定,编译器无法推导出模板参数 K 和 V。我希望该函数适用于具有任何类型对的任何容器;所以我想避免为 map<K,V>
、list<pair<K,V>>
、vector<pair<K,V>>
等编写单独的模板函数
因此,我不得不按如下方式修改模板函数签名,以使其按我想要的方式工作:
template<typename C,
typename K = remove_const_t<C::value_type::first_type>,
typename V = C::value_type::second_type>
vector<vector<K>> partition_keys(const C& input);
有更好的方法吗?根据 C
的 value_type
推导 K
和 V
的类型是一个好习惯吗?此外,调用者有可能为 K
和 V
.
还要注意我是如何通过调用 remove_const_t
来删除键类型的常量的,因为对于 map
,C::value_type::first_type
是 const
类型而标准不是允许创建 const
类型的集合。
很好。如果你不喜欢模板参数中的混乱,你可以将键类型直接放在 return 类型中,可能是尾随形式:
template <typename C>
auto partition_keys(const C& input)
-> vector<vector<remove_const_t<typename C::value_type::first_type>>>;
或者依靠 return 类型推导来实现正常功能并完全省略 return 类型:
template <typename C>
auto partition_keys(const C& input)
{
vector<vector<remove_const_t<typename C::value_type::first_type>>> result;
//...
return result;
}
你做的是对的,更具体地说:
template<typename C,
typename Pair = typename C::value_type,
typename Key = std::remove_const_t<typename Pair::first_type>,
typename Value = typename Pair::first_type
>
vector<vector<Key>> partition_keys(const C& input)
是正确的(Demo)。但是,如果您需要对不同的模板函数使用类似的类型分解,例如:
....repeat above templated type decomposition....
vector<vector<Key>> sorted_keys(const C& input);
....repeat above templated type decomposition....
vector<vector<Key>> filtered_keys(const C& input);
可能打字太多了。在这种情况下,您可以创建一个简单的特征 class 来帮助您。
template<typename T>
struct PTraits{
using pair_type = typename T::value_type;
using key_type = std::remove_const_t<typename pair_type::first_type>;
using value_type = typename pair_type::second_type;
};
template<typename T>
using KeyTypper = typename PTraits<T>::key_type;
然后用作...
template<typename C, typename Key = KeyTypper<C>>
vector<vector<Key>> partition_keys(const C& input);
template<typename C, typename Key = KeyTypper<C>>
vector<vector<Key>> sorted_keys(const C& input);
template<typename C, typename Key = KeyTypper<C>>
vector<vector<Key>> filtered_keys(const C& input);