Why can't I infer the template argument for this function?

I am trying to create a function template, remove a value from a vector by specifying a key:

template < typename Value, typename Map, typename Key > void RemoveValue( Map& m, const Key& k, const Value& v, std::function<bool(const Value&)> f) { auto it1 = m.find(k); if (it1 == m.end()) { return; } auto vs = it1->second; auto it2 = std::find_if(vs.begin(), vs.end(), f); if (it2 == vs.end()) { return; } vs.erase(it2); if (vs.empty()) { m.erase(it1); } } 

When I use it:

 RemoveValue(entityToTags, &entity, tag, [&](const Tag& t){ return t == tag; }); 

WITH

 const Entity& entity, const Tag& tag std::map<const Entity*, std::vector<Tag>> entityToTags; 

I have to specify Tag , i.e. RemoveValue<Tag>(entityToTags, &entity, tag, [&](const Tag& t){ return t == tag; }); to successfully compile.

How can I not explicitly specify <Tag> , and tell the compiler this?

I am using VS2012.

Thanks!

+2
source share
2 answers

You can just take f an arbitrary type and not force it in std::function . This makes more sense, as it can even be effective, and the standard library does it widely. Therefore, change the function as follows:

 template < typename Value, typename Map, typename Key, typename Functor > void RemoveValue( Map& m, const Key& k, const Value& v, Functor f) { auto it1 = m.find(k); if (it1 == m.end()) { return; } auto vs = it1->second; auto it2 = std::find_if(vs.begin(), vs.end(), f); if (it2 == vs.end()) { return; } vs.erase(it2); if (vs.empty()) { m.erase(it1); } } 
+4
source

You should add an error message to your question ...

Anyway, I used CLang ++ to compile it, and the error is:

 test.cpp:47:5: error: no matching function for call to 'RemoveValue' RemoveValue(entityToTags, &entity, tag, [&](const Tag &t) { return t == tag; }); ^~~~~~~~~~~ test.cpp:15:6: note: candidate template ignored: could not match 'function<bool (const type-parameter-0-0 &)>' against '<lambda at t.cpp:47:45>' void RemoveValue( 

That is, to infer the type Tag , the compiler must use the third argument Tag and the fourth. The latter is of type std::function<bool(const Value&)> , but you pass a lambda. Yes, lambda is converted to this type, but it is not that type, therefore the automatic output for Tag fails.

The solution would be to pass a value of the real type std::function<bool(const Value&)> :

 std::function<bool(const Tag&)> f = [&](const Tag &t) { return &t == &tag; }; RemoveValue(entityToTags, &entity, tag, f); 

Or use static_cast<>() if you want, but I would find this line too long.

+2
source

Source: https://habr.com/ru/post/1258384/


All Articles