提问人:Simon 提问时间:8/24/2023 最后编辑:DailyLearnerSimon 更新时间:8/26/2023 访问量:97
C++ 从文件中读取数据并转换为类的模板类型
c++ read data from file and convert to template type of class
问:
以下情况:
template <typename NumberType = double>
class A
{
//constructur, destructor,...
//member variable
std::vector<std::vector<NumberType> matrix_;
//member function
void read(std::ifstream fileIn)
{
std::string line, word;
unsigned int row = 0;
while (std::getline(fileIn, line))
{
std::istringstream lineStream(line);
unsigned int col = 0;
while (std::getline(lineStream, word, ','))
{
matrix_[row][col] = std::stod(word); // how to convert to NumberType?
col++;
}
row++;
}
}
};
我从 csv 文件中读取类似矩阵的数据,并希望将条目存储在一个容器中,该容器的类型是类中的模板类型。目前,我只为 实例化了类,所以我硬编码以进行测试。NumberType = double
std::stod(word)
但是如何将字符串转换为?NumberType 可以是 float、double、long double,...,但不能是 string、unsigned int、int,...word
NumberType
答:
3赞
wohlstad
8/24/2023
#1
您可以从中创建一个 std::istringstream
,然后使用其运算符 >>
来分析数值(因为它具有标准数值类型的重载)。word
您可以将以下方法添加到您的类中,并使用它代替 .GetNumber
std::stod
#include <sstream>
#include <iostream>
template <typename NumberType = double>
class A
{
// ...
public:
static NumberType GetNumber(std::string const& word)
{
std::istringstream ss{ word };
NumberType val{};
ss >> val; // here the proper overload will be called according to the type NumberType
return val;
}
};
int main()
{
std::cout << A<float>::GetNumber("123.123") << "\n";
std::cout << A<double>::GetNumber("456.456") << "\n";
}
输出:
123.123
456.456
注意:
上面的方法实际上与类无关,可以放在任何地方。
我将其作为类的一部分发布,以匹配 OP 的代码,并明确它应该在哪里使用。GetNumber
A
A
评论
0赞
Ahmed AEK
8/24/2023
这样一来,您就要为每次转换一个号码支付高昂的本地化成本......如果你知道你正在读取一个数字,你应该避免使用字符串。
1赞
wohlstad
8/24/2023
我同意,如果这是一个瓶颈,它应该被优化。但是 OP 要求一种适用于多种类型的通用方法,这是一种方法。
0赞
Caleth
8/24/2023
有什么理由把它包装在一个类中吗?
0赞
wohlstad
8/24/2023
@Caleth 我把它包装在一个类中,只是因为它与 OP 的发布代码匹配,具有相同的类名和模板参数名称(这样就很清楚它应该去哪里和使用)。除此之外没有真正的原因。我在答案中添加了一个注释。
4赞
Pepijn Kramer
8/24/2023
#2
对于您要支持的类型,我将使用显式转换函数。 这样一来,您就不会将转换留给机会(隐式转换和/或可能不正确的转换)。
#include <string>
template<typename NumberType>
NumberType ConvertTo(const std::string& from)
{
static_assert(false, "no conversion for this type yet");
}
// provide specializations for supported conversions
template<>
double ConvertTo<double>(const std::string& from)
{
return std::stod(from);
}
template<>
int ConvertTo<int>(const std::string& from)
{
return std::stoi(from);
}
template <typename NumberType = double>
class A
{
//constructur, destructor,...
//member variable
std::vector < std::vector<NumberType> matrix_;
//member function
void read(std::ifstream fileIn)
{
std::string line, word;
unsigned int row = 0;
while (std::getline(fileIn, line))
{
std::istringstream lineStream(line);
unsigned int col = 0;
while (std::getline(lineStream, word, ','))
{
// Use the template conversion function here :
matrix_[row][col] = ConvertTo<NumberType>(word);
col++;
}
row++;
}
}
};
0赞
Ahmed AEK
8/24/2023
#3
由于您只期望浮点数、双倍数、长双倍数,只需使用 std::stold,并让隐式转换将缩小转换为浮点数或双倍数,因此窄转换的成本是无法衡量的,并且您不会失去精度。
如果你也期待一个 int,那么你应该使用其他答案。
评论
1赞
Pepijn Kramer
8/24/2023
应避免石膏变窄。{} 初始值设定项不允许这样做是有原因的。这一切都留下了对“隐式”行为的转换,在大型项目中,这种行为最终总是会咬你。
评论
word
stringstream
operator<<
stringstream
istringstream
line
std::getline
lineStream
std::getline
stringstream
istringstream