【问题标题】:how can I get this function template to work reguardless of whether I pass a string literal or a string object?无论我传递的是字符串文字还是字符串对象,如何让这个函数模板工作?
【发布时间】:2020-08-03 09:51:10
【问题描述】:

我有以下函数模板,它接受任何类型的映射并返回与某个键关联的值或调用站点提供的默认值:

template <template <typename Key, typename Val, typename ...Args> typename C, typename Key, typename Val, typename ...Args>
Val get_or_default(C<Key, Val, Args...> const& my_map, Key const& k, Val const& v)
{
    typename C<Key, Val, Args...>::const_iterator const it = my_map.find(k);
    return (it != my_map.end()) ? it->second : v;
}

当我这样调用函数时:

// initialize map
    std::map<std::string, int> m1{ {"jim",1},{"mark",2},{"sally",3} };
// call get_or_default with std::string as key arg
    std::cout << get_or_default(m1, std::string("jim"), -1) << std::endl;

一切都按预期工作,但是当我像这样调用函数时:

std::cout << get_or_default(m1, "jim", -1) << std::endl;

我收到以下错误消息:

error C2782: 'Val get_or_default(const C<Key,Val,Args...> &,const Key &,const Val &)': template parameter 'Key' is ambiguous

我认为参数Key 是模棱两可的,因为它是在地图模板中使用std::string 调用的,但get_or_default 的第二个参数是const char*

无论我传递的是字符串对象还是字符串文字,如何才能让这个函数工作?

非常感谢您的帮助。

【问题讨论】:

    标签: c++ templates stdstring


    【解决方案1】:

    由于您对 Key 模板参数的推导有冲突,您可以简单地将 Key 参数之一设为非推导上下文。

    首先提供一个简单的类型标识结构:

    template<typename T>
    struct I { using type = T; };
    

    然后像这样使用它:

    template <template <typename Key, typename Val, typename ...Args> typename C,typename Key, typename Val, typename ...Args>
    Val get_or_default(C<Key, Val, Args...> const& my_map, typename I<Key>::type  const &k, Val const& v)
    {
        typename C<Key, Val, Args...>::const_iterator const it = my_map.find(k);
        return (it != my_map.end()) ? it->second : v;
    }
    

    您可以稍微简化一下。删除模板模板参数名称,因为它们无论如何都不会被使用。此外,您可以使用 auto 作为迭代器类型。此外,可变参数似乎没有用于任何目的。

    template <template <typename, typename> typename C, typename Key, typename Val>
    Val get_or_default(C<Key, Val> const& my_map, typename I<Key>::type const &k, Val const& v)
    {
        auto const it = my_map.find(k);
        return (it != my_map.end()) ? it->second : v;
    }
    

    这是一个有效的demo

    【讨论】:

    • 效果很好!我还为 value 参数添加了另一个类型标识结构,因为我在那里遇到了同样的问题。
    • 太好了。不过,请查看@dev65 的答案。您可能根本不需要这种额外的复杂性。
    【解决方案2】:

    这应该适合你:

    template<class C, class Key, class Val>
    Val get_or_default(C const& mp, Key const& k, Val const& v)
    {
        typename C::const_iterator it = mp.find(k);
        return (it != mp.end()) ? it->second : v;
    }
    

    如果您想要更好的类型限制和错误消息并且 c++ 20 是一个选项,那么概念就是要走的路

    【讨论】:

    • 如果我在 val 参数中传递字符串文字,这似乎不起作用。出于某种原因,它仅将字符串文字转换为映射键的 std::string 。这是我在我的问题中所要求的,所以你没有错,这有效,但@cigien 的答案适用于任意数量的参数。
    猜你喜欢
    • 1970-01-01
    • 2012-10-10
    • 2021-02-24
    • 2016-06-11
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多