Search code examples
c++typesprintfwrappertypecasting-operator

C++ Type Wrapper printf prints wrong value for float


I tried to write a wrapper class for fundamental types but ran into a problem when using printf.

For some reason printf works with int but not with float. std::cout however works with both just fine.

printf works properly of course when i explicitly cast to float.

template <typename T>
class Type
{
public:
    Type() : _mData() {}
    Type(const T& _data) : _mData(_data) {}

    operator T() const { return _mData; }
    operator std::string() const { return std::to_string(_mData); }

private:
    T _mData;
};

int main(void)
{
    Type<int> someInt(200);

    std::cout << "int" << std::endl;
    std::cout << "std::cout: " << someInt <<std::endl; 
    printf("printf: %d\n\n", someInt);


    Type<float> someFloat(300.3);
    std::cout << "float" << std::endl;
    std::cout << "std::cout: " << someFloat <<std::endl; 
    printf("printf: %f\n\n", someFloat);

    return 0;
}

output:
int
std::cout: 200
printf: 200

float
std::cout: 300.3
printf: 0.000000

Why does it work with int?

Why does it not work with float?

How can i get it to work properly without explicit casting?


Solution

  • Why does it work with int?

    It is UB. On your particular machine, it happens to work.

    Why does it not work with float?

    For the same reason as above.

    How can i get it to work properly without explicit casting?

    Dirrectly, you cannot. printf was created for C, at a time when C++ wasn't there (and OOP was not a consideration in the design of printf). Because of this, printf cannot be extended for new types.

    You could create a wrapper function that does the conversion for types supported by printf (explicitly) and calls printf internally. This is cumbersome, error prone and so on.

    This is one of the major advantages c++ iostreams have over the [s|f]printf family of functions.