Шаблон C ++: как использовать 2 typenames, в то время как только 1 является вводом функции? - PullRequest
1 голос
/ 28 апреля 2020

Для простого куска кода, показанного ниже:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <unordered_map>
#include <vector>
using namespace std;

static void print(const vector<int>& v) {
    copy(
        begin(v),
        end(v),
        ostream_iterator<int>{cout, ", "}
    );
    cout << endl;
}

int main() {
    vector<pair<int, string>> v {1, 2, 3, 4, 5};

    cout << endl << "In vector:" << endl;
    print(v);

    return 0;
}

Я попытался использовать шаблонное программирование для целей печати, так как я хочу обобщить container для любого типа (vector, map, list, et c), а также элемент любого типа (int, double, et c).

template <typename C, typename T>
static void print(const C& container) {
    copy(
        begin(container),
        end(container),
        ostream_iterator<T>{cout, ", "}
    );
    cout << endl;
}

Однако он не скомпилируется :

In function 'int main()':
prog.cc:31:12: error: no matching function for call to 'print(std::vector<int>&)'
   31 |     print(v);
      |            ^
prog.cc:18:13: note: candidate: 'template<class C, class T> void print(const C&)'
   18 | static void print(const C& container) {
      |             ^~~~~
prog.cc:18:13: note:   template argument deduction/substitution failed:
prog.cc:31:12: note:   couldn't deduce template parameter 'T'
   31 |     print(v);
      |            ^

Я предполагаю, что typename T не является явным вводом через функцию print(), скорее, он вызывается ostream_iterator<int>{cout, ", "}, который компилятор не знает, как определить его тип (почему ?).

Мне интересно, как передать оба typename (C и T) в функцию print(), хотя вводится только typename C?

Ответы [ 2 ]

3 голосов
/ 28 апреля 2020

Вам либо нужно явно указать тип T при вызове print (например, print(v, int), либо вы пишете print так, что он получает тип значения самого контейнера. Обычный способ сделать это использовать typename C::value_type, который присутствует во всех стандартных контейнерах:

template <typename C>
void print(const C& container) {
    using T = typename C::value_type;
    copy(
        begin(container),
        end(container),
        ostream_iterator<T>{cout, ", "}
    );
    cout << endl;
}

Если вам не нравится этот способ, или ваш контейнер не всегда может иметь член value_type, то вы можете легко получить тип значения напрямую:

template <typename C>
void print(const C& container) {
    using T = std::remove_const_t<decltype(*std::cbegin(container))>;
    copy(
        std::cbegin(container),
        std::cend(container),
        ostream_iterator<T>{cout, ", "}
    );
    cout << endl;
}
2 голосов
/ 28 апреля 2020

Вам не нужно указывать второй параметр шаблона. Большинство контейнеров STL имеют член value_type для этой цели. Итак, ваша функция должна быть:

template <typename C, typename T = typename C::value_type>
static void print(const C& container) {
    copy(
        begin(container),
        end(container),
        ostream_iterator<T>{cout, ", "}
    );
    cout << endl;
}
...