-3
$ file testfile.txt
testfile.txt: ASCII text

$ cat testfile.txt 
aaaabbbbccddef

#include <iostream>
#include <fstream>
#include <string>
#include <cstdint>
typedef uint8_t byte; // <-------- interesting
typedef std::basic_ifstream<byte> FileStreamT;
static const std::string FILENAME = "testfile.txt";
int main(){
    FileStreamT file(FILENAME, std::ifstream::in | std::ios::binary);
    if(!file.is_open())
        std::cout << "COULD NOT OPEN FILE" << std::endl;
    else{
        FileStreamT::char_type buff;
        file.read(&buff,1);
        std::cout << (SOMECAST)buff; // <------- interesting
    }
    std::cout << "done" << std::endl;
}

根据 typedef 中的内容以及将其转换为(或未转换)的内容,它会做各种愚蠢的事情。

它恰好适用于'typedef char'并且没有演员表。(如预期的那样,当转换为 int 时为 97)

uint8_t 和 int8_t 都将打印

  • 没有演员表什么都没有

  • 转换为 char 或 unsigned char 时什么都没有

  • 当转换为 int 或 unsigned 时为 8(尽管 ASCII 'a' 应为 97)

我以某种方式设法打印了一个“�”字符,但忘记了它是哪种情况。

为什么我会得到这些奇怪的结果?

给未来读者的注意事项:

从给出的答案中得出结论:仅使用 char (或标准也提到的宽字符之一)实例化流,否则您不会收到编译器警告和静默失败

标准保证这些东西是非常可悲的

故事的寓意:避免使用 C++

4

1 回答 1

4

的声明template std::basic_ifstream是:

template< 
    class CharT, 
    class Traits = std::char_traits<CharT>
> class basic_ifstream;

C++03 标准 (21.1/1) 要求库定义std::char_traits<CharT>for CharT= char,的特化wchar_t

C++11 标准 (C++11 21.2/1) 要求库定义std::char_traits<CharT>for CharT= char, char16_t, char32_t, 的特化wchar_t

如果您没有使用您正在编译的标准指定的 2[4] 类型之一进行实例化std::basic_ifstream<Other>Other那么行为将是未定义的,除非您自己my_char_traits<Other>根据需要定义然后实例化 std::basic_ifstream<Other,my_char_traits<Other>>

继续回应 OP 的评论。

请求一个std::char_traits<Other>不会引发模板实例化错误:定义模板以便您可以专门化它,但默认(非专门化)实例化很可能是错误的,Other 或者实际上对于任何给定CharT的,错误的方式不满足标准的要求对于每个 C++03 § 21.1.1/C++11 § 21.2.1 的字符特征类

您怀疑 typedef 可能会阻碍为 -ed 类型选择模板特化,typedefuint8_tint8_t 是基本字符类型的 typedef 这一事实可能导致std::basic_ifstream<byte>FCT 是别名基本字符类型不同。std::basic_ifstream<FCT>

忘记那个怀疑。typedef是透明的。您似乎相信typedef之一int8_t并且uint8_t必须是char,在这种情况下 - 除非 typedef 以某种方式干扰模板解析 -basic_ifstream您测试过的行为不端的实例之一必须是std::basic_ifstream<char>

typedef char byte但是,无害的事实又如何呢?认为要么int8_tuint8_t=char是错误的。你会发现int8_t 是 的别名是signed charuint8_t别名unsigned char。但既不是signed char也不unsigned char是同一类型char

C++03/11 § 3.9.1/1

普通字符、有符号字符和无符号字符是三种不同的类型

因此,char_traits<int8_t>char_traits<uint8_t>都是模板的默认、非专业化实例,char_traits您无权期望它们满足该标准对 字符特征的要求。

您发现没有不当行为的一个测试用例是 for byte= char。那是因为char_traits<char>是库提供的标准特化。

您观察到的所有不当行为与您在以下方面替代的类型之间的联系SOMECAST

std::cout << (SOMECAST)buff; // <------- interesting

没有。由于您的测试文件包含 ASCII 文本,因此是标准保证读取它的basic_ifstream<char> 唯一实例。basic_ifstream如果您在typedef char byte程序中使用读取文件,那么您说您替换的所有转换都不会产生意外结果:SOMECAST= charor unsigned charwill outputaSOMECAST= intor unsigned intwill output 97

所有的不当行为都源于使用 标准不保证的某种类型进行basic_ifstream<CharT>实例化。CharT

于 2013-07-26T08:06:44.053 回答