具有基元类型的模板向量类型

template vector type with primitive type

本文关键字:类型 向量      更新时间:2023-10-16

我想用基元类型(intfloatdouble(和向量类型(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;
}

您可以将其封装在类模板中,该模板可以是部分专用的。

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。

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

实时

根据定义函数的方式,您需要对函数进行部分专业化——这在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){};

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