This project is read-only.

How do I get SafeInt to work with boost::format?

Jan 22, 2015 at 10:55 AM
Edited Jan 22, 2015 at 11:09 AM
Hello,

I was trying out the idea of replacing every int with SafeInt; however, there are some problems.

It seems that you cannot just write one to cout. That's quickly fixed:
template <typename CharT, typename TraitsT, typename IntT, typename ErrT>
typename std::basic_ostream<CharT, TraitsT> & operator<<(typename std::basic_ostream<CharT, TraitsT> &stream, const typename SafeInt<IntT, ErrT> &val) {
    return stream << static_cast<IntT>(val);
}
Sometimes it's more convenient to use boost::format. However, I can't seem to get this work:
#include <iostream>
#include <boost/format.hpp>
#include <SafeInt.hpp>

template <typename CharT, typename TraitsT, typename IntT, typename ErrT>
typename std::basic_ostream<CharT, TraitsT> & operator<<(typename std::basic_ostream<CharT, TraitsT> &stream, const typename SafeInt<IntT, ErrT> &val) {
    return stream << static_cast<IntT>(val);
}

template <typename Ch, typename Tr, typename Alloc, typename IntT, typename ErrT>
typename boost::basic_format<Ch, Tr, Alloc> & operator%(typename boost::basic_format<Ch, Tr, Alloc> &fmt, const typename SafeInt<IntT, ErrT> &val) {
    return fmt % static_cast<IntT>(val);
}

int main() {
    using namespace std;
    using namespace boost;

    typedef SafeInt<size_t> SizeT;
    SizeT x = 12;
    //cout << x << endl;
    auto fmt = format("Size is %1%") % x;
    cout << fmt << endl;
}
With Visual C 2013 I get these errors:
main.cpp(26): error C2593: 'operator %' is ambiguous
          boost/format/format_class.hpp(63): could be 'boost::basic_format<char,std::char_traits<char>,std::allocator<char>> &boost::basic_format<char,std::char_traits<char>,std::allocator<char>>::operator %<SizeT>(const T &)'
          with
          [
              T=SizeT
          ]
          SafeInt.hpp(6633): or       'SafeInt<size_t,CPlusPlusExceptionHandler> operator %<size_t,boost::basic_format<char,std::char_traits<char>,std::allocator<char>>,CPlusPlusExceptionHandler>(U,SafeInt<size_t,CPlusPlusExceptionHandler>)'
          with
          [
              U=boost::basic_format<char,std::char_traits<char>,std::allocator<char>>
          ]
          main.cpp(13): or       'boost::basic_format<char,std::char_traits<char>,std::allocator<char>> &boost::operator %<char,std::char_traits<char>,std::allocator<char>,size_t,CPlusPlusExceptionHandler>(boost::basic_format<char,std::char_traits<char>,std::allocator<char>> &,const SafeInt<size_t,CPlusPlusExceptionHandler> &)'
          while trying to match the argument list '(boost::basic_format<char,std::char_traits<char>,std::allocator<char>>, SizeT)'
main.cpp(27): error C3536: 'fmt': cannot be used before it is initialized
Isn't my operator% the more specialized version?

Thanks,
Florin
Jan 22, 2015 at 11:20 AM
A workaround for this would be to create my own class, derived from boost::format. This way my operator would take precedence.
template <class Ch>
class BasicFormat : public boost::basic_format<Ch> {
    typedef boost::basic_format<Ch> BaseT;
public:
    BasicFormat(const char *psz) : BaseT(psz) {}

    template <typename T>
    BasicFormat & operator%(const typename T &val) {
        BaseT::operator%(val);
        return *this;
    }

    template <typename IntT, typename ErrT>
    BasicFormat & operator%(const typename SafeInt<IntT, ErrT> &val) {
        BaseT::operator%(static_cast<IntT>(val));
        return *this;
    }
};
Still, it somehow feels fragile and wrong...
Mar 14, 2015 at 3:25 AM
I haven't tested SafeInt with either of those. While I like the fix above, I wouldn't want to put it into the main library because I don't like to create dependencies on other headers unless I have to. I think I will document your approach as a potential fix. The other obvious fix is to just unbox it back to it's base type when calling <<.