C++ 从文件中读取数据并转换为类的模板类型

c++ read data from file and convert to template type of class

提问人:Simon 提问时间:8/24/2023 最后编辑:DailyLearnerSimon 更新时间:8/26/2023 访问量:97

问:

以下情况:

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 = doublestd::stod(word)

但是如何将字符串转换为?NumberType 可以是 float、double、long double,...,但不能是 string、unsigned int、int,...wordNumberType

C++ 文件 模板 强制转换

评论

0赞 wohlstad 8/24/2023
你可以把 放入 a 并使用它的 .wordstringstreamoperator<<
0赞 Simon 8/24/2023
在一个或像我这样做吗?stringstreamistringstreamline
0赞 wohlstad 8/24/2023
为什么你再次使用 on(当它已经是你从上一行得到的行时)?std::getlinelineStreamstd::getline
0赞 wohlstad 8/24/2023
我在想,但也许也可以使用。stringstreamistringstream
0赞 Simon 8/24/2023
@wohlstad我在这里两次使用 std::getline 发现了类似的方法:stackoverflow.com/questions/34218040/......但是,如果您有更简单的策略来读取 csv 数据,我将不胜感激您的意见。

答:

3赞 wohlstad 8/24/2023 #1

您可以从中创建一个 std::istringstream,然后使用其运算符 >> 来分析数值(因为它具有标准数值类型的重载)。word

您可以将以下方法添加到您的类中,并使用它代替 .GetNumberstd::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 的代码,并明确它应该在哪里使用。
GetNumberAA

评论

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
应避免石膏变窄。{} 初始值设定项不允许这样做是有原因的。这一切都留下了对“隐式”行为的转换,在大型项目中,这种行为最终总是会咬你。