为什么我不能为此函数推导出模板参数?

时间:2014-07-07 08:49:32

标签: c++ templates

我尝试制作一个功能模板,从矢量中删除一个值,给出一个键:

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

当我使用它时:

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

使用:

const Entity& entity, const Tag& tag

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

我必须指定Tag,即RemoveValue<Tag>(entityToTags, &entity, tag, [&](const Tag& t){ return t == tag; });才能成功编译。

我怎样才能明确指定<Tag>,让编译器知道它?

我正在使用VS2012。

谢谢!

2 个答案:

答案 0 :(得分:4)

您可以简单地使用f任意类型,而不是将其强制转换为std::function。它更有意义,因为它甚至可以提高效率,标准库可以做到这一点。所以改变这样的功能:

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

答案 1 :(得分:2)

您应该将错误消息添加到您的问题中......

无论如何,我用CLang ++编译它,错误是:

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(

也就是说,要推断Tag的类型,编译器必须使用第3个参数tag和第4个参数。最后一个是std::function<bool(const Value&)>类型,但是你传递一个lambda。是的,lambda可以转换为该类型,但那个类型,因此Tag的自动扣除失败。

解决方案是传递真实类型std::function<bool(const Value&)>的值:

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

如果您愿意,可以使用static_cast<>(),但我会发现该行太长了。