11
#include <fstream>

int main()
{
    std::ifstream fin{ "" };
    size_t n = fin.tellg(); // ok
}

The code compiles ok. However, according to cppreference, I find fin.tellg() is a type of std::fpos, which doesn't define the ability to convert itself to size_t implicitly.

Any explanations?

xmllmx
  • 39,765
  • 26
  • 162
  • 323
  • 3
    `std::streampos` is an integer type that just *might* be compatible with `size_t` on your system. Just because there is no guarantee, doesn't mean that it *never* works. – Bo Persson Jan 18 '17 at 08:18
  • 1
    You should be particularly careful with such conversion if the file happens to be very large. – Sven Nilsson Jan 18 '17 at 08:21
  • 1
    It is theoretically possible that `std::fpos` is 64-bit while `size_t` is 32-bit. – rustyx Jan 18 '17 at 08:25
  • @BoPersson `basic_istream::tellg()` returns `pos_type`; `pos_type` is `Traits::pos_type`; `char_traits::pos_type` is `streampos`; `streampos` is `fpos`, which is not an integral type? – BoBTFish Jan 18 '17 at 08:26
  • 2
    @BoB - Ok, I missed one step. `fpos` is implicitly convertible to `streamoff`, which is the integer type. – Bo Persson Jan 18 '17 at 08:31
  • Your question raises another: why do you need to convert it to a `size_t` in the first place? – user657267 Jan 18 '17 at 08:49

2 Answers2

6

You are right about the fact that it returns an std::fpos. Now let's look at how it's defined:

template<class _Statetype>
    class fpos {<...>}

fpos also does have a conversion operator for converting into the streamoff type which is "stream offset" type:

__CLR_OR_THIS_CALL operator streamoff() const
    {   // return offset
    return ((streamoff)(_Myoff + _FPOSOFF(_Fpos)));
    }

On my machine streamoff happens to be defined as typedef _Longlong streamoff;, I would believe it's something similar on your machine. This is why it can be converted to type_t, however nothing prevents it from being larger than type_t, so be careful.

SingerOfTheFall
  • 29,228
  • 8
  • 68
  • 105
4

"OK" on your platform. Not necessarily OK on all platforms. Whether in practice that means much depends on the circumstances. For example, on a 32-bit system, the file may be 4GB or larger, and thus not fit in the 32-bit size_t, where std::fpos is a 64-bit value and does hold the size of the file.

If the n is used to determine the length of the file or some such, serious problems may occur if you misjudge the total size - overwriting old data, or if you load the file and then save it based on that, you'd lose some or all of the data.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • 3
    Just a minor note: The problem with loading and saving the file is more complicated - and cannot really be solved by a different type. The reason is that if the file-size doesn't fit in size_t then the file contents is unlikely to fit in memory. – Hans Olsson Jan 18 '17 at 10:12