C++ 从‘std::__tuple... {aka ‘unsigned int*’} 到 ‘uint32_t’ {aka ‘unsigned int’} 的转换会失去精度

问题描述

您可能不得不原谅我,因为我是 C++ 新手,并且可能在我迄今为止编写的代码中犯了一些基本错误

static tuple<read_result,uint8_t*> m_scan_record(bool skip,uint32_t& size,FILE* file)
{
    read_result result;
    
    tuple<read_result,uint32_t*> rd_rec_size_result = m_read_generic_t<uint32_t>(file);

    result = (read_result)get<0>(rd_rec_size_result);
    
    if (result != read_success )
    {
        return tuple<read_result,uint8_t*>(result,nullptr);
    }

    size = (uint32_t) get<1>(rd_rec_size_result);

    if ( skip )
    {
        fseek(file,size,SEEK_CUR);
    }
// ...
}

template<typename T>
static tuple<read_result,T*> m_read_generic_t(FILE* file)
{
    T ret = 0;
    
    read_result result = m_read_from_file_to_buffer(&ret,sizeof(T),file);

    if (result == read_success)
    {
        return tuple<read_result,T*>(result,&ret);
    }

    return tuple<read_result,nullptr);
}

当我编译这段代码时,我收到了这个错误

cast from ‘std::__tuple_element_t<1,std::tuple<read_result,unsigned int*> >’ {aka ‘unsigned int*’} to ‘uint32_t’ {aka ‘unsigned int’} loses precision [-fpermissive]

我的意图以及我应该做什么/发生什么:

  1. m_scan_record 的声明中,size 参数是用 & 声明的,它旨在允许我通过引用传递值,类似于使用 { {1}} c# 关键字

  2. 调用了泛型(模板)函数 REF,该函数以指定的类型 m_read_generic_t 调用,因此(根据其定义)将返回类型为 {{1} }

  3. 一旦我得到了 <unit32_t> 返回的元组,我想取元组的第二个值指向的 tuple<read_result,uint32_t*> 值,并将该值放入 {{1}上面第 1 点提到的变量,然后调用函数可能会在堆栈上进一步访问该变量。

  4. 从以上几点你可以看出我的意图(我很感激我可能离现实很远!)就是在这一行:

    size = (uint32_t) get(rd_rec_size_result);

我所做的只是获取一个“指向”值并将其放入匹配类型的变量中,就像经常引用的教科书示例一样:

m_read_generic_t

很明显,这不是我的代码真正发生的事情,因为如果是这样,我认为不需要演员表。但是如果我删除它,就像这样:

unit32_t

然后我得到一个编译时错误

size

因此,我相信我做错了什么 - 但我不知道是什么。这与我从元组中取出指针的方式有关吗?或者在从 uint32_t* 获取 uint32_t 值时还有其他事情发生吗?

这一切都在 Ubuntu 20.04、FWIW 上的 C++ 环境中

非常感谢您的任何/所有建议;请放轻松!

解决方法

tuple<read_result,uint32_t*> rd_rec_size_result = ...

这个元组的第二个成员,正如这里明确声明的,是一个指向 uint32_t 的指针。这就是 uint32_t * 在 C++ 中的意思。

size = (uint32_t) get<1>(rd_rec_size_result);

这会检索 uint32_t * 并尝试将其转换为 uint32_t。 C++ 不能以这种方式工作。尽管可以强制进行这种转换,但您的编译器完全有权利相信无论此代码试图做什么,它都一定是错误的。

也许我最初想知道,您的意图是取消引用指针。无论如何,这就是编译错误的原因。如果您的意图是真正取消引用此指针,那么只需将其更改为

size = *get<1>(rd_rec_size_result);

然而,这不会是你麻烦的结束。即使在修复了这个编译错误之后,这样显示的代码仍然会很糟糕,很糟糕。

这是因为 m_read_generic_t 返回一个指向本地对象的指针,该对象将在函数返回时被销毁,并且在此处尝试取消引用该指针将导致 demons fly out of your nose

这里真正的修复是将m_read_generic_t更改为返回一个指针作为元组中的第二个值排在第一位,从而在第一时间消除编译错误。