简体   繁体   中英

Why can't I deduce template argument for this function?

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 , ie 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!

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

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.

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