C++中std::cin读取值至units库类型变量的异常问题排查
问题:C++ Units库类型的std::cin输入与计算异常问题
开发C++程序时,尝试通过std::cin读取用户输入值,存入Units库定义的带单位类型(dimless_t、curr_t、len_t等)供后续公式计算,遇到两个问题:
- 直接读取时编译报错:
std::cin不是已定义类型 - 使用
static_cast转换类型后无编译错误,但程序输出结果异常(如RSE为-nan mT)
未尝试类型转换的代码
// ISO C++20: #include <algorithm> #include <cmath> // contiene std::sqrt #include <fstream> #include <iostream> #include <numbers> #include <string> #include <vector> // ISO C++23: #include <cppexten/generator> #include <cppexten/print> #include <cppexten/ranges> namespace stdx = std::experimental; // biblioteca de terceros: #include <boost/tokenizer.hpp> // tokenizador para extraer los valores en una línea del CSV #include <dlib/optimization.h> // contiene el método LM de regresión no-lineal #include <units/format.h> #include <units/math.h> #include <units/isq/si/length.h> #include <units/generic/dimensionless.h> //#include <units/isq/si/electric_current.h> #include <units/isq/si/electric_field_strength.h> // Por que ampere está aquí y no en electric_current? #include <units/isq/si/magnetic_induction.h> #include <units/isq/si/permeability.h> namespace un = units; namespace usi = units::isq::si; using len_t = usi::length<usi::millimetre>; // Tipo de longitud en milimetros using curr_t = usi::electric_current<usi::ampere>; // Tipo de corriente en Amperios using mag_ind_t = usi::magnetic_induction<usi::millitesla>; // Tipo de intensidad del campo magnético en militeslas using perm_t = usi::permeability<usi::henry_per_metre>; // Tipo de permeabilidad del vacío en Henry · metro^(-1) using dimless_t = un::quantity<un::dim_one, un::one, float>; // Tipo sin unidades dimless_t const N ; // número de espiras, adimensional curr_t const I ; // Corriente que pasa por el solenoide en Amperios len_t const L ; // Longitud del solenoide en milímetros len_t const D ; auto main() -> int { std::cout<<"Insert number of loops of the solenoid: "; std::cin>>N; std::cout<<"Insert intensity of the current: "; std::cin>>I; std::cout<<"Insert lenght of the solenoid: "; std::cin>>L; std::cout<<"Insert diametre of the solenoid: "; std::cin>>D; }
尝试类型转换后的代码片段
float cN ; float cI ; float cL ; float cD ; auto N = static_cast<dimless_t>(cN); // número de espiras, adimensional auto I = static_cast<curr_t>(cI); // Corriente que pasa por el solenoide en Amperios auto L = static_cast<len_t>(cL); // Longitud del solenoide en milímetros auto D = static_cast<len_t>(cD);
输出对比
- 程序原本正常输出:
Insert the path of the CSV file (C:/Users/user_name/Desktop/file_name.csv): C:\Users\Escritorio\Europea\Tercero\Computacion_avanzada\magnetic_data_no_z_correction.csv Factor de corrección z_0 = 5.28333 mm Permeabilidad magnética μ0 = 1.1579e-06 H/m | μ0/(4 * pi * 10^-7) = 0.92143 H/m RSE = 0.797024 mT
- 转换后错误输出:
Insert number of loops of the solenoid: 100.0 Insert intensity of the current: 1.0 Insert lenght of the solenoid: 50.0 Insert diametre of the solenoid: 10.0 Insert the path of the CSV file (C:/Users/user_name/Desktop/file_name.csv): C:\Users\alvar\OneDrive\Escritorio\Europea\Tercero\Computacion_avanzada\magnetic_data_no_z_correction.csv Factor de corrección z_0 = 5 mm Permeabilidad magnética μ0 = 1e-06 H/m | μ0/(4 * pi * 10^-7) = 0.795775 H/m RSE = -nan mT
问题分析与解决方法
原因分析
直接读取编译错误:
- Units库的
quantity类型默认未提供std::istream重载运算符,无法直接通过std::cin >>读取值到带单位变量中。 - 原代码中变量被声明为
const,const变量无法被赋值,这是编译失败的核心原因。
- Units库的
转换后结果异常:
- 转换代码中声明的
float变量(cN、cI等)未初始化,会持有随机垃圾值,直接static_cast到Units类型后,后续计算必然出现NaN等异常结果。
- 转换代码中声明的
修正方案
方案1:先读取基础类型,再构造Units类型
移除变量的const修饰,先将用户输入读取到基础数值类型(如float),再用合法值构造带单位的变量:
#include <algorithm> #include <cmath> #include <fstream> #include <iostream> #include <numbers> #include <string> #include <vector> #include <cppexten/generator> #include <cppexten/print> #include <cppexten/ranges> namespace stdx = std::experimental; #include <boost/tokenizer.hpp> #include <dlib/optimization.h> #include <units/format.h> #include <units/math.h> #include <units/isq/si/length.h> #include <units/generic/dimensionless.h> #include <units/isq/si/electric_field_strength.h> #include <units/isq/si/magnetic_induction.h> #include <units/isq/si/permeability.h> namespace un = units; namespace usi = units::isq::si; using len_t = usi::length<usi::millimetre>; using curr_t = usi::electric_current<usi::ampere>; using mag_ind_t = usi::magnetic_induction<usi::millitesla>; using perm_t = usi::permeability<usi::henry_per_metre>; using dimless_t = un::quantity<un::dim_one, un::one, float>; int main() { dimless_t N; curr_t I; len_t L; len_t D; float input_val; std::cout << "Insert number of loops of the solenoid: "; std::cin >> input_val; N = dimless_t{input_val}; std::cout << "Insert intensity of the current: "; std::cin >> input_val; I = curr_t{input_val}; std::cout << "Insert lenght of the solenoid: "; std::cin >> input_val; L = len_t{input_val}; std::cout << "Insert diametre of the solenoid: "; std::cin >> input_val; D = len_t{input_val}; // 后续公式计算代码... }
方案2:实现std::istream重载
为Units的quantity类型实现std::istream重载运算符,之后可直接用std::cin >>读取:
#include <istream> template<typename Unit, typename Rep = float> std::istream& operator>>(std::istream& is, un::quantity<Unit, Rep>& q) { Rep val; is >> val; q = un::quantity<Unit, Rep>{val}; return is; } // 在main函数中直接使用: // std::cout << "Insert number of loops of the solenoid: "; // std::cin >> N;
注意事项
- 确保输入为合法数值,避免非数值输入导致的读取失败。
- 如果需要支持用户输入带单位的字符串(如
"100 mm"),需要额外解析单位部分并对应到Units库的单位类型。
内容的提问来源于stack exchange,提问作者alvarito mendez
相关产品推荐
相关产品推荐

