我想用原语类型(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;
}发布于 2019-10-31 03:45:13
定义函数的方式需要对函数进行部分专门化--这在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){};在原始的非矢量版本中,将读取任何可用的值,并在最后丢弃所有的值。这是故意的吗?
发布于 2019-10-31 03:45:03
您可以将其包装在类模板中,该类模板可以是部分专门化的。
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;
}https://stackoverflow.com/questions/58636425
复制相似问题