简体   繁体   中英

Adding methods with template specialization

I have a hash table container called Map with the following method:

Value Map<Key, Value>::valueFor(const Key& key);

Unfortunately, the most used case is for Key = std::string where we usually call the method with string literals such as:

const Value v = map.valueFor("my_key");

We loose a few cycles creating the std::string . Therefore, I would like to add an overload

Value Map<std::string, Value>::valueFor(const char* key);

when Key = std::string . I am sure that the compiler can even compute the hash at compile time with such a signature which would also help to speedup things.

Is there a way to do that in C++11 without template specializing the whole Map class and rewrite all the methods?

You can just add another overload valueFor(char const * key) . Probably you then also want to disable this overload with SFINAE if the Key is not std::string .

#include <iostream>
#include <string>
#include <type_traits>

template < typename Key, typename Value >
struct Map
{
    Value valueFor(Key const& key)
    {
        std::cout << "valueFor(const Key& key)\n";
        return Value{};
    }

    template < typename _Key = Key,
               typename = typename std::enable_if< std::is_same < _Key, std::string >::value >::type >
    Value valueFor(char const * key)
    {
        std::cout << "valueFor(char const * key)\n";
        return Value{};
    }
};

int main()
{
    Map<std::string, int> map;
    int v = map.valueFor("my_key");

    Map<int, int> other_map;
  //int v = other_map.valueFor("my_key"); // BOOM!
}

Just weaken your type requirements. Your valueFor doesn't (need to) care what type the argument is, so long as the expression hash<Key>(arg) is valid.

So, you can template valueFor on its argument type, and just specialise your hash function and if necessary your key comparator.

eg. (untested, and using C++17 string_view for brevity)

template <typename K>
struct Hasher
{
  static size_t hash(K const &k) { return std::hash<K>()(k); }
};
template <>
struct Hasher<std::string>
{
  static size_t hash(std::string const &s) {
    return std::hash<std::string>()(s);
  }
  static size_t hash(std::string_view const &sv) {
    return std::hash<std::string_view>()(sv);
  }
  static size_t hash(const char *cstr) {
    return std::hash<std::string_view>()({cstr});
  }
};

template <typename Key, typename Value>
template <typename KeyArg>
Value Map<Key,Value>::valueFor(KeyArg&& arg)
{
    auto hash = Hasher<Key>::hash(std::forward<KeyArg>(arg));
    // ...
}

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