шаблон векторного типа с примитивным типом - PullRequest
0 голосов
/ 31 октября 2019

Я хочу создать шаблон функции с типом примитива (int, float, double) и векторным типом (vector<int>, vector<float>, vector<double>). Ниже мой код. Я хотел бы знать, есть ли способ для шаблона parseKeyValue() с меньшим количеством дублирования кода при построении различных векторных случаев. Спасибо!

#include <iostream>
#include <typeinfo>
#include <vector>
#include <string>
#include <sstream>
#include <iterator>


using namespace std;


template<class T> T parseKeyValue(stringstream& ss){
    T value;
    while(ss >> value){};
    return value;
}

template<> vector<string> parseKeyValue(stringstream& ss){
    vector<string> value;
    string item;
    while(ss >> item) value.push_back(item);
    return value;
}

template<> vector<int> parseKeyValue(stringstream& ss){
    vector<int> value;
    int item;
    while(ss >> item) value.push_back(item);
    return value;
}


template<typename T>
ostream& operator<<(ostream& os, const vector<T>& v){
    std::copy(v.begin(), v.end(), std::ostream_iterator<T>(os, " "));
    return os;
}


int main(){

    stringstream ss("1-2-3 7-8-9");
    vector<string> t = parseKeyValue< vector<string> >(ss);
    cout << t << endl;

    stringstream ss2("123 789");
    vector<int> t2 = parseKeyValue< vector<int> >(ss2);
    cout << t2 << endl;

    stringstream ss3("123 789");
    int t3 = parseKeyValue< int >(ss3);
    cout << t3 << endl;

    return 0;
}

Ответы [ 2 ]

3 голосов
/ 31 октября 2019

Вы можете обернуть его в шаблон класса, который может быть частично специализированным.

template<class T> 
struct Wrapper {
    static T parseKeyValue(stringstream& ss){
        T value;
        while(ss >> value){};
        return value;
    }
};

template<class T> 
struct Wrapper<std::vector<T>> {
    static vector<T> parseKeyValue(stringstream& ss){
        vector<T> value;
        T item;
        while(ss >> item) value.push_back(item);
        return value;
    }
};

template<class T> T parseKeyValue(stringstream& ss){
    return Wrapper<T>::parseKeyValue(ss);
}

LIVE

Или применить SFINAE сперегрузка шаблона.

template <typename T>
struct is_vector : std::false_type {};
template <typename T>
struct is_vector<std::vector<T>> : std::true_type {};

template<class T> 
std::enable_if_t<!is_vector<T>::value, T>
parseKeyValue(stringstream& ss) {
    T value;
    while(ss >> value){};
    return value;
}

template<class T> 
std::enable_if_t<is_vector<T>::value, T>
parseKeyValue(stringstream& ss) {
    T value;
    typename T::value_type item;
    while(ss >> item) value.push_back(item);
    return value;
}

LIVE

2 голосов
/ 31 октября 2019

Для определения ваших функций вам потребуются частичные специализации для ваших функций, что недопустимо в C ++. Даже если это было законно, у вас нет параметров для вывода типа шаблона, поэтому вам всегда придется явно указывать аргументы шаблона:

std::vector<int> v = parseKeyValue<std::vector<int>>(...);
//                                ^        ^       ^

, поскольку вычет из присваивания переменной не являетсявозможно.

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

template <typename T>
void parseKeyValue(T& t, std::istream& s);

template <typename T>
void parseKeyValue(std::vector<T>&, std::istream& s);

И у вас даже может быть вариант для универсальных контейнеров:

template <typename T, template <typename> class Container >
void parseKeyValue(Container<T>, std::istream& s);

Обратите внимание, что я изменил параметр с std::stringstream на std::istream, что является менее ограничительным, поэтому вы можете использовать функции, например, с std::cin.

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

int n;
parseKeyValue(n, std::cin); // selects non-container overload
std::vector<int> v;
parseKeyValue(v, std::cin); // selects vector overload, as more specialised
std::list<int> l;
parseKeyValue(l, std::cin); // selects generic container overload

Примечание:

while(ss >> value){};

в исходной не векторной версии будет считывать любые доступные значения и будет отбрасывать все, кромеочень последнийЭто предназначено?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...