编译器是如何从map中找出模板类型的

how did the compiler figure out the template types from map

本文关键字:类型 map 编译器      更新时间:2023-10-16

我是一个使用模板的胆小用户,通常遵循常规的示例案例。

因此,看到以下代码,我感到非常惊讶。

template<typename Table> void set(Table& tbl,
const typename Table::key_type& key,
const typename Table::mapped_type& attr)
{
  typename Table::iterator iter = tbl.find(key);
  if (iter != tbl.end()) {
    iter->second = attr;
  } else {
    typedef typename Table::key_type TableKey;
    typedef typename Table::mapped_type TableNonKey;
    tbl.insert( std::pair<TableKey,TableNonKey>(key,attr) );
  }
}
template<typename Table> void show(Table& tbl)
{
  for (typename Table::iterator iter = tbl.begin();
    iter != tbl.end(); ++iter) {
    cout << iter->second << endl;
  }
}
int main(){
  std::map<int, int> table_obj;
  set(table_obj, 1, 2);
  show(table_obj);
}

在编译show/set函数时,编译器如何知道Table是std::map,并能够从中推导出Table::key_type和Table::mapped_type?模板还有其他类似的用例吗?

main中,编译器知道"table"的类型,然后使用Koenig Lookup/ADL在这种情况下找到一个合适的set,因为只有一个。

申报

template<typename Table> void set(Table& tbl,
const typename Table::key_type& key,
const typename Table::mapped_type& attr);

实施

template<typename Table> void set(Table& tbl,
const typename Table::key_type& key,
const typename Table::mapped_type& attr) {
  typename Table::iterator iter = tbl.find(key);
  if (iter != tbl.end()) {
    iter->second = attr;
  } else {
    typedef typename Table::key_type TableKey;
    typedef typename Table::mapped_type TableNonKey;
    tbl.insert( std::pair<TableKey,TableNonKey>(key,attr) );
  }
}

CCD_ 3和CCD_ 4是来自std::map的typedef。

如果你这样叫"set"

std::vector<int> NotAMap;
set(NotAMap, 1, 2);

环回仍然会找到"set",并且在开始时发现Table可能是std::vector,但std::vector没有mapped_type,所以它被拒绝作为候选者。

您的代码:

  std::map<int, int> table_obj;
  set(table_obj, 1, 2);
  show(table_obj);

您的问题:

编译器如何知道Table是std::map并且能够推导out Table::key_type和Table::mapped_type编译show/set函数?

答:因为table_obj的类型是已知的。

只要设身处地为编译器着想。在第1行中,您可以看到table_objstd::map<int, int>。那么在第2行和第3行,你还应该做什么呢?只能用Table=std::map<int, int>实例化模板函数setshow。没有歧义。

如果你试图用其他类型实例化函数,就会出现错误:

set<double>(table_obj, 1, 2);                    // error
set<void>(table_obj, 1, 2);                      // error
set<std::map<int *, char *> >(table_obj, 1, 2);  // error
set<std::map<double, int> >(table_obj, 1, 2);    // error
set<std::map<int, int> >(table_obj, 1, 2);       // OK

正如您所看到的,指定类型是冗余。因此C++允许您省略它。

该语言的这一功能被称为模板参数推导


模板还有其他类似的用例吗?

几乎每一次使用标准算法。

考虑这个例子:

#include <algorithm>
#include <vector>
int main()
{
    std::vector<int> v;
    std::find(v.begin(), v.end(), 123);
}

如果没有模板参数推导,最后一行必须写成:

int main()
{
    std::vector<int> v;
    std::find<std::vector<int>::iterator, int>(v.begin(), v.end(), 123);
}