首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >模板向量类型与原语类型

模板向量类型与原语类型
EN

Stack Overflow用户
提问于 2019-10-31 03:11:12
回答 2查看 173关注 0票数 0

我想用原语类型(intfloatdouble)和向量类型(vector<int>vector<float>vector<double>)来模板一个函数。下面是我的密码。我想知道在构建不同的向量情况时,是否有一种方法可以用较少的代码复制来模板parseKeyValue()。谢谢!

代码语言:javascript
复制
#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;
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-10-31 03:45:13

定义函数的方式需要对函数进行部分专门化--这在C++中是不合法的。即使这是合法的,您也没有用于推断模板类型的参数,因此始终必须显式地指定模板参数:

代码语言:javascript
复制
std::vector<int> v = parseKeyValue<std::vector<int>>(...);
//                                ^        ^       ^

因为从赋值到变量的演绎是不可能的。

如果将函数签名更改为填充函数参数,则可以使用重载操作:

代码语言:javascript
复制
template <typename T>
void parseKeyValue(T& t, std::istream& s);

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

您甚至可以为通用容器提供一个变体:

代码语言:javascript
复制
template <typename T, template <typename> class Container >
void parseKeyValue(Container<T>, std::istream& s);

请注意,我将参数从std::stringstream更改为std::istream,限制较小,因此您也可以使用std::cin等函数。

这样,您就不依赖于部分专门化,而且还可以从模板参数推导中获益:

代码语言:javascript
复制
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

附带说明:

代码语言:javascript
复制
while(ss >> value){};

在原始的非矢量版本中,将读取任何可用的值,并在最后丢弃所有的值。这是故意的吗?

票数 2
EN

Stack Overflow用户

发布于 2019-10-31 03:45:03

您可以将其包装在类模板中,该类模板可以是部分专门化的。

代码语言:javascript
复制
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);
}

活着

或者在模板重载的情况下应用SFINAE

代码语言:javascript
复制
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;
}

活着

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58636425

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档