c++ - 这是 boost::filesystem 中的错误吗?为什么 boost::filesystem::path::string() 在 Windows 和 Linux 上没有相同的签名?

标签 c++ linux c++11 boost boost-filesystem

我正在尝试使用成员函数 string()< 将 boost::filesystem::path 的 vector 转换为 std::string/。我写了这篇文章,它在 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)));

现在我转到 gcc(6.3,Debian Stretch),我的代码给出了链接错误,上面的签名不存在。要修复它,我必须将代码更改为:

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

PS:我知道 lambda 解决方案更简单,但出于必要,我现在改用了它。

起初,我认为 MSVC 更宽容,但后来我切换回 Windows 并得到相反的链接错误,第一个签名是正确的。我查看了源代码(1.64,path.hpp),这是我发现的:

#   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

所以我看到的推理是,在 Windows 上,因为它默认不使用 UTF-8,所以有一个临时转换。但为什么 boost 不对 Windows 和 Linux 使用相同的 API?最坏的情况是,它会花费一个字符串的拷贝。对吧?

我应该使用 path::string() 的替代方法来获得跨平台 API 稳定性吗?

最佳答案

您可能正在使用旧版本的 Boost.Filesystem 库。 Boost 1.64 says签名是:

string string(const codecvt_type& cvt=codecvt()) const;

返回类型与平台无关;它应该始终是一个值,而不是一个引用。请注意,这(大部分)匹配 the C++17 FileSystem library's definition .因此,如果您在文档中说它是一个值时获得引用,那么其中一个是错误的。因此,无论哪种方式都存在错误。

然而,应该注意的是,在 C++ 标准中(因此,也可能在 Boost 中),成员函数的假设是它们不必完全匹配文档规范。例如,成员函数可以具有标准中未列出的其他默认参数。只要它按照说明是可调用的,那就是有效的实现。

因此,您根本不应该期望 std::mem_fn 像这样工作。。使用 C++ 标准措辞,不应假设 path::string 可以转换为具有该签名的成员指针。因此,虽然它可能不一致,但您可以获得成员指针的期望可能不是 Boost 支持的接口(interface)。

无论是否是错误,您都可以使用 lambda 轻松解决此问题:

std::transform(
    users.begin(), users.end(), std::back_inserter(usersStrs),
    [](const auto &pth) -> decltype(auto) {return pth.string();});

它比 std::mem_fn 版本看起来更简洁。 decltype(auto) 会在返回引用时防止不必要的复制。

关于c++ - 这是 boost::filesystem 中的错误吗?为什么 boost::filesystem::path::string() 在 Windows 和 Linux 上没有相同的签名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45664628/

相关文章:

linux - 从 linux 文件中删除 ^@ 字符

linux - 如何在 Linux 上运行 libsvm?

c++ - 如何对 std::list 的一部分进行排序?

c++ - 我可以在不使用 new 的情况下在 C++ 中实现工厂方法模式吗?

c++ - 为什么我不能将引用作为函数参数传递给std::async

linux - 在 bash 中使用从字符串解析的数组

C++11 外部作用域变量声明为 auto

c++ - 为什么不能默认模板模板参数?

c++ - 多个模板匹配只检测一个匹配项

c++ - 未定义标识符/未声明