简体   繁体   中英

how can I get this function template to work reguardless of whether I pass a string literal or a string object?

I have the following function template that takes any type of map and returns either the value associated with a certain key or a default value provided at the call site:

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

when I call the function this way:

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

everything works as expected, however when I call the function like:

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

I get the following error message:

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

I think that the parameter Key is ambiguous because it is being called with std::string in the map template but as const char* for the second parameter of get_or_default

How can I get this function to work regardless of whether I am passing a string object or a string literal?

Thank you for any help at all.

Since you are getting conflicting deduction for the Key template parameter, you can simply make one of the Key arguments a non-deduced context.

First provide a simple type-identity struct:

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

and then use it like this:

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

You can simplify this a bit. Remove the template template parameter names, since they are not used anyway. Also, you can use auto for the iterator type. Also, the variadic arguments don't seem to be used for any purpose.

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

Here's a working demo .

This should work for you:

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

If you want better type restrictions and error messages and c++ 20 is an option then concepts are the way to go

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM