You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

问题分析与解决方法

原因分析

  1. 直接读取编译错误:

    • Units库的quantity类型默认未提供std::istream重载运算符,无法直接通过std::cin >>读取值到带单位变量中。
    • 原代码中变量被声明为const,const变量无法被赋值,这是编译失败的核心原因。
  2. 转换后结果异常:

    • 转换代码中声明的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 01:05:18