从函数模板参数中自动推论对容器的元素类型

Automatically deducing element type of pair container from the function template argument

本文关键字:类型 元素 参数 函数模板      更新时间:2023-10-16

我想编写一个模板函数,该功能取下一个键值对的容器(例如map<K,V>vector<pair<K,V>>),然后返回一个键容器。例如:

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);

有更好的方法吗?根据Cvalue_type推断KV的类型是一个好习惯吗?另外,有可能明确通过KV的无效论据。

还要注意如何通过调用remove_const_t删除密钥类型的constness,因为对于mapC::value_type::first_typeconst类型,并且该标准不允许创建const类型的集合。

您正在做正确的方式,更具体地说:

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)

是正确的(演示)。但是,如果您需要对不同的模板函数使用类似类型的分解,例如:

....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);

可能要做的太多了。在这种情况下,您可以举办一个简单的特质类来帮助您。

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);

demo

很好。如果您不喜欢模板参数中的混乱,则可以将密钥类型直接放在返回类型中,可能是在尾随形式中:

template <typename C>
auto partition_keys(const C& input)
    -> vector<vector<remove_const_t<typename C::value_type::first_type>>>;

或依靠正常功能的返回类型扣除额,并完全省略返回类型:

template <typename C>
auto partition_keys(const C& input)
{
    vector<vector<remove_const_t<typename C::value_type::first_type>>> result;
    //...
    return result;
}