dimanche 13 août 2017

Is this a bug in boost::filesystem? Why does boost::filesystem::path::string() not have the same signature on Windows and Linux?

I'm trying to convert a vector of boost::filesystem::path to std::string, using the member function string(). I wrote this and it was working fine on Windows (MSVC 14, 2015):

std::transform(
    users.begin(), users.end(), std::back_inserter(usersStrs),
    std::mem_fn(static_cast<const std::string (PathType::*)() const>(
        &PathType::string)));

Now I moved to gcc (6.3, Debian Stretch), and my code gave linking error that the signature above doesn't exist. To fix it, I had to change the code to:

std::transform(
    users.begin(), users.end(), std::back_inserter(usersStrs),
    std::mem_fn(static_cast<const std::string& (PathType::*)() const>(
        &PathType::string)))

PS: I know a lambda solution is easier, which I now switched to, out of necessity.

At first, I thought MSVC is more tolerant, but then I switched back to Windows and got the opposite linking error, that the first signature is correct. I went to the source code (1.64, path.hpp), and this is what I found:

#   ifdef BOOST_WINDOWS_API
    const std::string string() const
    {
      std::string tmp;
      if (!m_pathname.empty())
        path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(),
        tmp);
      return tmp;
    }
//...
#   else   // BOOST_POSIX_API
    //  string_type is std::string, so there is no conversion
    const std::string&  string() const { return m_pathname; }
//...
#   endif

So the reasoning I see is that on Windows, since it doesn't use UTF-8 by default, there's a temporary conversion. But why wouldn't boost use the same API for both Windows and Linux? Worst case, it'll cost a copy of a string. Right?

Is there an alternative to path::string() that I should be using to have cross-platform API stability?

Aucun commentaire:

Enregistrer un commentaire