как я могу заставить этот шаблон функции работать независимо от того, передаю ли я строковый литерал или строковый объект? - PullRequest
1 голос
/ 20 апреля 2020

У меня есть следующий шаблон функции, который принимает любой тип карты и возвращает либо значение, связанное с определенным ключом, либо значение по умолчанию, предоставленное на сайте вызова:

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

, когда я вызываю функцию this путь:

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

I думаю, что параметр Key является неоднозначным, потому что он вызывается с std::string в шаблоне карты, но как const char* для второго параметра get_or_default

Как я могу заставить эту функцию работать независимо передаю ли я строковый объект или строковый литерал?

Спасибо за любую помощь.

Ответы [ 2 ]

0 голосов
/ 20 апреля 2020

Это должно работать для вас:

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 - это опция, то концепции - это путь к go

0 голосов
/ 20 апреля 2020

Поскольку вы получаете противоречивое вычитание для параметра шаблона 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 для типа итератора. Кроме того, аргументы variadi c, похоже, не используются для каких-либо целей.

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 .

...