Reputation: 3035
I try to make a function template, remove a Value from a vector, giving 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 must 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 let the compiler know it?
I am using VS2012.
Thanks!
Upvotes: 2
Views: 162
Reputation: 98368
You should add the 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 deduce the type of Tag
the compiler must use the 3rd argument tag
and the 4th. The last one is of type std::function<bool(const Value&)>
but you pass a lambda. Yes, the lambda is convertible to that type, but it is not that type, so the automatic deduction for Tag
fails.
The solution would be to pass a value of 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 prefer, but I would find that line too long.
Upvotes: 2
Reputation: 171127
You could simply take an f
of arbitrary type, instead of forcing it into std::function
. It makes more sense, as it could even be fore efficient, and the standard library does that extensively. So change the function like this:
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);
}
}
Upvotes: 4