C++ 函数模板和模糊模板参数

C++ 函数模板和模糊模板参数,c++,templates,stdmap,C++,Templates,Stdmap,我有几个std::map,我正在尝试编写一个函数模板Lookup,如下所示 当键是指针或标量时,函数模板工作正常,但如果键是std::string,则会出现问题 #include <iostream> #include <map> // Usage : // bool valueisinmap = Lookup(themap, thekey, thevalue); template <typename TK, typename TV> bool Look

我有几个
std::map
,我正在尝试编写一个函数模板
Lookup
,如下所示

当键是指针或标量时,函数模板工作正常,但如果键是
std::string
,则会出现问题

#include <iostream>
#include <map>

// Usage :
//   bool valueisinmap = Lookup(themap, thekey, thevalue);
template <typename TK, typename TV>
bool Lookup(std::map<TK, TV>& map,  TK key, TV& value)
{
  auto it = map.find(key);
  if (it != map.end())
  {
    value = it->second;
    return true;
  }
  else
  {
    return false;
  }
}

int main()
{
    std::map<std::string, std::string> m;
    m.insert(std::make_pair("2", "two"));

    std::string x;
    std::string key = "2";

    if (Lookup(m, key, x))
      std::cout << "OK\n";

    if (Lookup(m, "2", x))  // problem here
      std::cout << "OK\n";
}

按值传递,如果
的类型为
std::string
,则复制一份。有没有一种方法可以通过引用传递
(或者一些C++14和plus magic)并且仍然能够使用
查找(m,“2”,x)

解决这个问题的一种方法是为键类型引入一个单独的类型参数,如下所示:

template <typename TKM, typename TK, typename TV>
bool Lookup(const std::map<TKM, TV>& map, const TK& key, TV& value)
{
  auto it = map.find(key);
  if (it != map.end())
  {
    value = it->second;
    return true;
  }
  else
  {
    return false;
  }
}
模板
布尔查找(常量标准::映射和映射、常量TK和键、TV和值)
{
auto it=map.find(键);
if(it!=map.end())
{
值=它->秒;
返回true;
}
其他的
{
返回false;
}
}

只要
TK
可以隐式转换为
TKM
Lookup
就可以使用
TK
类型的键以及具有键类型
TKM
的映射来调用。首先,可以单独推断密钥类型(
typename K
如下)。其次,您希望将键作为
const
限定引用传递,并使用C++14透明比较函数(
typename Comp
)设置映射,以避免不必要的副本(有关透明比较器的详细信息,请参阅)

模板
布尔查找(常量标准::映射和映射、常量K和键、TV和值)
{
//和以前一样。。。
}
std::map m;
std::less
指定为
std::map
比较类型可确保的重载#3和#4可用


请注意,我另外对map参数本身进行了限定,因为
查找
模板不会对其进行修改。

您可以为
as引入另一个模板参数,另一种方法是将其从:


在这种情况下,
键的值是多少?
std::type\u identity\u t
不是空结构吗?@TonvandenHeuvel
std::type\u identity
只有一个成员类型,
std::type\u identity\u t
TK
相同实际上,它们都引用类型
TK
,只是它使模板参数不可推断,然后,
TK
将仅从第一个参数推导,避免了类型推导中的歧义。啊,是的,我现在看到了一个有趣的解决方案。无法用C++17编译它。换句话说,我需要声明
std::map m而不是
std::map m
每次键都是
std::string
?不幸的是,是的。@Jabberwocky,我不会这么说,除非您不准备支付从非
std::string
键到
std::string
键的隐式转换的费用,否则在执行查找时,您应该使用透明比较器。
template <typename TKM, typename TK, typename TV>
bool Lookup(const std::map<TKM, TV>& map, const TK& key, TV& value)
{
  auto it = map.find(key);
  if (it != map.end())
  {
    value = it->second;
    return true;
  }
  else
  {
    return false;
  }
}
template <typename TK, typename TV, typename Comp, typename K>
bool Lookup(const std::map<TK, TV, Comp>& map,  const K& key, TV& value)
{
   // Same as before...
}

std::map<std::string, std::string, std::less<>> m;
template <typename TK, typename TV>
bool Lookup(std::map<TK, TV>& map, const std::type_identity_t<TK>& key, TV& value)
template<typename T> struct type_identity { typedef T type; };