2014-10-14 7 views
1

Я робкий пользователь с шаблоном и обычно выполняю обычные примеры случаев.как компилятор вычислил типы шаблонов с карты

поэтому, я очень удивлен, увидев следующий код.

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

Как компилятор знает, что таблица является станд :: карта и возможность вычитать из таблицы :: key_type и таблицу :: mapped_type из него, когда речь идет о компиляции шоу/установить функцию? Существуют ли другие аналогичные примеры использования с шаблоном?

+2

компилятор узнает, что 'Table' должен быть' станд :: Карта 'через процесс называется [шаблон вывод аргумента] (http://en.cppreference.com/w/cpp/language/template_argument_deduction) –

+1

key_type и mapped_type - typedefs в классе карты. В качестве параметра шаблона можно использовать любой класс, который имеет эти typedefs и функции, которые вы вызываете, такие как find и end. –

+0

Обратите внимание, что 'Таблица :: key_type' и' Таблица :: mapped_type' не подлежат вычету (но «Таблица» была ранее вычтена). – Jarod42

ответ

1

В main компилятор знает тип «таблицы», а затем используйте 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)); 
    } 
} 

key_type и mapped_type являются определения типов из std::map.

Если вы обозвал «установить» этот путь

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

loopup все равно бы нашли «множество» и при запуске обнаружил, что таблица может быть станд :: вектор, но станд :: вектор Безразлично» t имеет mapped_type, поэтому он отклоняется в качестве кандидата.

+0

Можем ли мы поместить основной и шаблон в разные единицы компиляции? если да, то каким образом компилятор вычитает, что «таблица» - это тип карты? – pepero

+0

Шаблон должен быть видимым в блоке, который использует его (объявление), а затем где-то его реализация должна быть создана с конкретным типом, чтобы иметь возможность связывать. – Surt

1

Ваш код:

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

Ваш вопрос:

Как компилятор знает, что таблица является станд :: карта и возможность вычитать из таблицы :: key_type и таблица :: mapped_type от него, когда дело доходит до компилировать шоу/функцию набора?

Ответ: поскольку известен тип table_obj.

Просто поставьте себя в положение компилятора. В строке 1 вы видите, что table_obj - это std::map<int, int>. Итак, в строках 2 и 3, что еще вы должны делать? Вы могут только экземпляр функции шаблона set и show с Table = std::map<int, int>. Нет никакой двусмысленности.

Если вы пытаетесь создать экземпляр функции с другими типами, ошибки будут происходить:

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++ позволяет опустить его.

Эта особенность этого языка называется template argument deduction.


Существуют ли какие-либо другие подобные случаи использования с шаблоном?

Практически любое использование стандартного алгоритма.

Рассмотрим следующий пример:

#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); 
} 
Смежные вопросы