1

Inspired by contains(), I want do declare contains(), fitting misc containers.

// for std::vector, std::list, ..           (1)
template<typename C, typename T>
bool contains(const C& container, const T& val) 
{
    return ::std::find(container.begin(), container.end(), val) != container.end();
}

// partial specialization for std::map       (2)
template<typename K, typename V>
bool contains(const ::std::map<K, V>& container, const K& key)
{
   // std::map.find() is better than std::find used in (1)
    return container.find(key) != container.end(); 
}

Following question, I want to add the functions to namespace the arguments belongs too.

Questions:

  1. Types of val from (1) and key from (2) are unknown. Does it mean I don't need to put the functions to any namespace or do I need to put them in std namespace, the containers belong to?

  2. Is it possible to improve (2) it will preferred by compiler than (1) for std::map, std::set, boost::unordered_map, boost::unordered_set?

  3. boost::algorithm::contains(). Do I need choose another name for my wrapper?

Community
  • 1
  • 1
dimba
  • 26,717
  • 34
  • 141
  • 196

4 Answers4

2

On number 3. you should place your version of contains in it's own namespace to avoid naming clashes. That's the purpose of namespaces.

Tony The Lion
  • 61,704
  • 67
  • 242
  • 415
2

(1) Don't add anything to the std namespace

(2) As Space_C0wb0y points out, (2) is not a partial specialization, but an overload. I'm not sure if this is standard behaviour, but on VS2008 this is resolved correctly (the overloaded version is used for map). In either case, I think a slighly better version would be:

template<typename C>
bool contains(const C & mapContainer, const typename C::key_type & key)
{
  // std::map.find() is better than std::find used in (1)
  return mapContainer.find(key) != mapContainer.end(); 
}

This is a partial specialization (T is specialized to C::key_type) and would work for all types that has the key_type typedef (e.g. std::map, boost::unordered_map etc.)

(3) Put in separate namespace (see @Tony's answer)

Sidenote: I'm not sure I think these functions should have the same name. If I saw a function contains() accepting a map + another argument I could think that (1) the function checks if the map contains an entry for the given value (e.g. some key has the value provided) or (2) the function checks if there is such an entry in the map (e.g. the provided value is a pair). Instead I would call the function contains_key() for maps.

Edit: After a bit of checking I suspect that the code above isn't compliant as it uses "template typedefs". This is not a standard C++ feature, but it seems that Visual Studio supports it in some cases. There's probably a workaround for this, but not one I'm clever enough to come up with now.

Community
  • 1
  • 1
larsmoa
  • 12,604
  • 8
  • 62
  • 85
  • @larsm I accept your Sidenote - I renamed functions to contains_val()/constains_key(). – dimba May 19 '11 at 13:46
  • @larsm Idea with const typename C::key_type is nice. However, compiler is unable to choose between (1) and your contains() for example for std::map – dimba May 19 '11 at 14:02
  • @dimba: It is? What compiler are you using? I'm not able to reproduce this issue (VS2008). – larsmoa May 19 '11 at 14:07
  • @dimba: I think I found the cause for this not working on GCC, see my edit. – larsmoa May 20 '11 at 06:52
  • @larsm IMHO your code is legal. You don't use "template typedefs". Thee problem that both versions has as 1st argument the container and as second T& (for (1)) and C::key_type& for your code. For std::map both overloaded contains() matches well and compiler don't know which to choose. – dimba May 20 '11 at 09:33
1

Yes, keep them in a separate namespace.

The only thing to place in the same namespace as the argument type is operator overloads, to allow for Koenig (argument-dependent) lookup. These are not overloaded operators. End of story.

Note how this also answer question 2.: how you make the compiler prefer your implementations:

 using myownversions::contains;

(assuming you named your namespace myownversions for now)

sehe
  • 374,641
  • 47
  • 450
  • 633
1
  1. You must not put them into the std namespace. This is forbidden. You can put them into any namespace you like.
  2. There is probably some SFINAE-magic you can do there, but I cannot come up with it in my own.
  3. See @Tony's answer.
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283