Remove path converting constructors from types convertible to path sources.

This causes ambiguities in users' code where the previously added conversion
from user-defined types that have a conversion to one of the path source
types:

  struct my_class
  {
    operator std::string() const;
  };

  std::string to_string(std::string const&);
  std::string to_string(boost::filesystem::path const&);

  to_string(my_class());

The above call is ambiguous as the conversion operator in my_class and
a converting constructor in boost::filesystem::path from my_class are
both available and have equivalent ranks.

Removing the conversion constructors from boost::filesystem::path
means users will have to explicitly cast their types to one of the
path source types before constructing path.

In order to preserve backward compatibility with operator== and operator!=
for paths that also accepted source types (path::string_type,
const path::value_type*), we have to update path::compare and comparison
operators to accept types that are convertible to source types.

Fixes https://github.com/boostorg/filesystem/issues/273.
This commit is contained in:
Andrey Semashev 2023-02-04 19:55:17 +03:00
parent 9a49c4f3f4
commit 5cefe7890f
5 changed files with 261 additions and 81 deletions

View File

@ -39,6 +39,11 @@
</td>
</table>
<h2>1.82.0</h2>
<ul>
<li>Fixed compilation errors that could have been caused by <code>path</code> conversion constructors being too permissive on the accepted arguments. (<a href="https://github.com/boostorg/filesystem/issues/273">#273</a>)</li>
</ul>
<h2>1.81.0</h2>
<ul>
<li><b>Deprecated:</b> <code>path</code> construction, assignment and appending from containers of characters, such as <code>std::vector&lt;char&gt;</code> or <code>std::list&lt;wchar_t&gt;</code>, is deprecated in <b>v3</b> and removed in <b>v4</b>. Please use string types or iterators instead.</li>

View File

@ -398,37 +398,37 @@ void convert(const wchar_t* from, const wchar_t* from_end, std::string& to, cons
// Source dispatch -----------------------------------------------------------------//
template< typename Source, typename Callback >
inline void dispatch(Source const& source, Callback cb, const codecvt_type* cvt = NULL);
typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt = NULL);
template< typename Callback >
BOOST_FORCEINLINE void dispatch(const char* source, Callback cb, const codecvt_type* cvt, ntcts_type_tag)
BOOST_FORCEINLINE typename Callback::result_type dispatch(const char* source, Callback cb, const codecvt_type* cvt, ntcts_type_tag)
{
cb(source, source + std::strlen(source), cvt);
return cb(source, source + std::strlen(source), cvt);
}
template< typename Callback >
BOOST_FORCEINLINE void dispatch(const wchar_t* source, Callback cb, const codecvt_type* cvt, ntcts_type_tag)
BOOST_FORCEINLINE typename Callback::result_type dispatch(const wchar_t* source, Callback cb, const codecvt_type* cvt, ntcts_type_tag)
{
cb(source, source + std::wcslen(source), cvt);
return cb(source, source + std::wcslen(source), cvt);
}
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch(Source const& source, Callback cb, const codecvt_type* cvt, string_class_tag)
BOOST_FORCEINLINE typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt, string_class_tag)
{
cb(source.data(), source.data() + source.size(), cvt);
return cb(source.data(), source.data() + source.size(), cvt);
}
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch(Source const& source, Callback cb, const codecvt_type* cvt, range_type_tag)
BOOST_FORCEINLINE typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt, range_type_tag)
{
std::basic_string< typename Source::value_type > src(source.begin(), source.end());
cb(src.data(), src.data() + src.size(), cvt);
return cb(src.data(), src.data() + src.size(), cvt);
}
#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4
template< typename Callback >
BOOST_FORCEINLINE void dispatch(std::vector< char > const& source, Callback cb, const codecvt_type* cvt, range_type_tag)
BOOST_FORCEINLINE typename Callback::result_type dispatch(std::vector< char > const& source, Callback cb, const codecvt_type* cvt, range_type_tag)
{
const char* data = NULL, *data_end = NULL;
if (!source.empty())
@ -436,11 +436,11 @@ BOOST_FORCEINLINE void dispatch(std::vector< char > const& source, Callback cb,
data = &source[0];
data_end = data + source.size();
}
cb(data, data_end, cvt);
return cb(data, data_end, cvt);
}
template< typename Callback >
BOOST_FORCEINLINE void dispatch(std::vector< wchar_t > const& source, Callback cb, const codecvt_type* cvt, range_type_tag)
BOOST_FORCEINLINE typename Callback::result_type dispatch(std::vector< wchar_t > const& source, Callback cb, const codecvt_type* cvt, range_type_tag)
{
const wchar_t* data = NULL, *data_end = NULL;
if (!source.empty())
@ -448,19 +448,19 @@ BOOST_FORCEINLINE void dispatch(std::vector< wchar_t > const& source, Callback c
data = &source[0];
data_end = data + source.size();
}
cb(data, data_end, cvt);
return cb(data, data_end, cvt);
}
#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4
// Defined in directory.hpp to avoid circular header dependencies
template< typename Callback >
void dispatch(directory_entry const& de, Callback cb, const codecvt_type* cvt, directory_entry_tag);
typename Callback::result_type dispatch(directory_entry const& de, Callback cb, const codecvt_type* cvt, directory_entry_tag);
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch(Source const& source, Callback cb, const codecvt_type* cvt)
BOOST_FORCEINLINE typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt)
{
path_traits::dispatch(source, cb, cvt,
return path_traits::dispatch(source, cb, cvt,
typename path_traits::path_source_traits< typename boost::remove_cv< Source >::type >::tag_type());
}
@ -552,35 +552,35 @@ struct make_dependent
};
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch_convertible_impl(const char* source, Callback cb, const codecvt_type* cvt)
BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(const char* source, Callback cb, const codecvt_type* cvt)
{
typedef typename path_traits::make_dependent< const char*, Source >::type source_t;
path_traits::dispatch(static_cast< source_t >(source), cb, cvt);
return path_traits::dispatch(static_cast< source_t >(source), cb, cvt);
}
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch_convertible_impl(const wchar_t* source, Callback cb, const codecvt_type* cvt)
BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(const wchar_t* source, Callback cb, const codecvt_type* cvt)
{
typedef typename path_traits::make_dependent< const wchar_t*, Source >::type source_t;
path_traits::dispatch(static_cast< source_t >(source), cb, cvt);
return path_traits::dispatch(static_cast< source_t >(source), cb, cvt);
}
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch_convertible_impl(std::string const& source, Callback cb, const codecvt_type* cvt)
BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::string const& source, Callback cb, const codecvt_type* cvt)
{
typedef typename path_traits::make_dependent< std::string, Source >::type source_t;
path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
}
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch_convertible_impl(std::wstring const& source, Callback cb, const codecvt_type* cvt)
BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::wstring const& source, Callback cb, const codecvt_type* cvt)
{
typedef typename path_traits::make_dependent< std::wstring, Source >::type source_t;
path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
}
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch_convertible_impl
BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl
(
boost::container::basic_string< char, std::char_traits< char >, void > const& source,
Callback cb,
@ -588,11 +588,11 @@ BOOST_FORCEINLINE void dispatch_convertible_impl
)
{
typedef typename path_traits::make_dependent< boost::container::basic_string< char, std::char_traits< char >, void >, Source >::type source_t;
path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
}
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch_convertible_impl
BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl
(
boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > const& source,
Callback cb,
@ -600,11 +600,11 @@ BOOST_FORCEINLINE void dispatch_convertible_impl
)
{
typedef typename path_traits::make_dependent< boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void >, Source >::type source_t;
path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
}
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch_convertible_impl
BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl
(
boost::basic_string_view< char, std::char_traits< char > > const& source,
Callback cb,
@ -612,11 +612,11 @@ BOOST_FORCEINLINE void dispatch_convertible_impl
)
{
typedef typename path_traits::make_dependent< boost::basic_string_view< char, std::char_traits< char > >, Source >::type source_t;
path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
}
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch_convertible_impl
BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl
(
boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > const& source,
Callback cb,
@ -624,7 +624,7 @@ BOOST_FORCEINLINE void dispatch_convertible_impl
)
{
typedef typename path_traits::make_dependent< boost::basic_string_view< wchar_t, std::char_traits< wchar_t > >, Source >::type source_t;
path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
}
#if !defined(BOOST_FILESYSTEM_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR)
@ -632,60 +632,62 @@ BOOST_FORCEINLINE void dispatch_convertible_impl
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch_convertible_impl(std::string_view const& source, Callback cb, const codecvt_type* cvt)
BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::string_view const& source, Callback cb, const codecvt_type* cvt)
{
typedef typename path_traits::make_dependent< std::string_view, Source >::type source_t;
path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
}
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch_convertible_impl(std::wstring_view const& source, Callback cb, const codecvt_type* cvt)
BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::wstring_view const& source, Callback cb, const codecvt_type* cvt)
{
typedef typename path_traits::make_dependent< std::wstring_view, Source >::type source_t;
path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
}
#endif // !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = NULL)
BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = NULL)
{
typedef typename boost::remove_cv< Source >::type source_t;
path_traits::dispatch_convertible_impl< source_t >(source, cb, cvt);
return path_traits::dispatch_convertible_impl< source_t >(source, cb, cvt);
}
#else // !defined(BOOST_FILESYSTEM_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR)
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch_convertible_sv_impl(std::string_view const& source, Callback cb, const codecvt_type* cvt)
BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_sv_impl(std::string_view const& source, Callback cb, const codecvt_type* cvt)
{
typedef typename path_traits::make_dependent< std::string_view, Source >::type source_t;
path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
}
template< typename Source, typename Callback >
BOOST_FORCEINLINE void dispatch_convertible_sv_impl(std::wstring_view const& source, Callback cb, const codecvt_type* cvt)
BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_sv_impl(std::wstring_view const& source, Callback cb, const codecvt_type* cvt)
{
typedef typename path_traits::make_dependent< std::wstring_view, Source >::type source_t;
path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
}
template< typename Source, typename Callback >
BOOST_FORCEINLINE typename boost::disable_if_c<
is_convertible_to_std_string_view< typename boost::remove_cv< Source >::type >::value
is_convertible_to_std_string_view< typename boost::remove_cv< Source >::type >::value,
typename Callback::result_type
>::type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = NULL)
{
typedef typename boost::remove_cv< Source >::type source_t;
path_traits::dispatch_convertible_impl< source_t >(source, cb, cvt);
return path_traits::dispatch_convertible_impl< source_t >(source, cb, cvt);
}
template< typename Source, typename Callback >
BOOST_FORCEINLINE typename boost::enable_if_c<
is_convertible_to_std_string_view< typename boost::remove_cv< Source >::type >::value
is_convertible_to_std_string_view< typename boost::remove_cv< Source >::type >::value,
typename Callback::result_type
>::type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = NULL)
{
typedef typename boost::remove_cv< Source >::type source_t;
path_traits::dispatch_convertible_sv_impl< source_t >(source, cb, cvt);
return path_traits::dispatch_convertible_sv_impl< source_t >(source, cb, cvt);
}
#endif // !defined(BOOST_FILESYSTEM_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR)

View File

@ -174,10 +174,10 @@ namespace path_traits {
// Dispatch function for integration with path class
template< typename Callback >
BOOST_FORCEINLINE void dispatch(directory_entry const& de, Callback cb, const codecvt_type* cvt, directory_entry_tag)
BOOST_FORCEINLINE typename Callback::result_type dispatch(directory_entry const& de, Callback cb, const codecvt_type* cvt, directory_entry_tag)
{
boost::filesystem::path::string_type const& source = de.path().native();
cb(source.data(), source.data() + source.size(), cvt);
return cb(source.data(), source.data() + source.size(), cvt);
}
} // namespace path_traits

View File

@ -227,6 +227,35 @@ private:
}
};
//! Path comparison operation
class compare_op;
friend class compare_op;
class compare_op
{
private:
path const& m_self;
public:
typedef int result_type;
explicit compare_op(path const& self) BOOST_NOEXCEPT : m_self(self) {}
BOOST_FORCEINLINE result_type operator() (const value_type* source, const value_type* source_end, const codecvt_type* = NULL) const
{
return m_self.compare(path(source, source_end));
}
template< typename OtherChar >
BOOST_FORCEINLINE result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = NULL) const
{
path src;
detail::path_traits::convert(source, source_end, src.m_pathname, cvt);
return m_self.compare(src);
}
};
struct sfinae_helper;
public:
class iterator;
friend class iterator;
@ -255,10 +284,7 @@ public:
typename Source,
typename = typename boost::enable_if_c<
boost::conjunction<
boost::disjunction<
detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >,
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >
>,
boost::negation< detail::path_traits::is_native_path_source< typename boost::remove_cv< Source >::type > >
>::value
>::type
@ -268,10 +294,7 @@ public:
template< typename Source >
path(Source const& source, typename boost::enable_if_c<
boost::conjunction<
boost::disjunction<
detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >,
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >
>,
boost::negation< detail::path_traits::is_native_path_source< typename boost::remove_cv< Source >::type > >
>::value
>::type* = NULL)
@ -285,23 +308,17 @@ public:
typename Source,
typename = typename boost::enable_if_c<
boost::conjunction<
boost::disjunction<
detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >,
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >
>,
boost::negation< detail::path_traits::is_native_path_source< typename boost::remove_cv< Source >::type > >
>::value
>::type
>
path(Source const& source, codecvt_type const& cvt)
explicit path(Source const& source, codecvt_type const& cvt)
#else
template< typename Source >
path(Source const& source, codecvt_type const& cvt, typename boost::enable_if_c<
explicit path(Source const& source, codecvt_type const& cvt, typename boost::enable_if_c<
boost::conjunction<
boost::disjunction<
detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >,
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >
>,
boost::negation< detail::path_traits::is_native_path_source< typename boost::remove_cv< Source >::type > >
>::value
>::type* = NULL)
@ -568,10 +585,7 @@ public:
template< typename Source >
typename boost::enable_if_c<
boost::disjunction<
detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >,
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >
>::value,
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
path&
>::type operator+=(Source const& source)
{
@ -710,10 +724,7 @@ public:
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
boost::disjunction<
detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >,
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >
>::value,
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
path&
>::type operator/=(Source const& source)
{
@ -947,6 +958,48 @@ public:
return BOOST_FILESYSTEM_VERSIONED_SYM(compare)(p);
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value,
int
>::type compare(Source const& source) const
{
return detail::path_traits::dispatch(source, compare_op(*this));
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
boost::conjunction<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >,
boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > >
>::value,
int
>::type compare(Source const& source) const
{
return detail::path_traits::dispatch_convertible(source, compare_op(*this));
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value,
int
>::type compare(Source const& source, codecvt_type const& cvt) const
{
return detail::path_traits::dispatch(source, compare_op(*this), &cvt);
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
boost::conjunction<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >,
boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > >
>::value,
int
>::type compare(Source const& source, codecvt_type const& cvt) const
{
return detail::path_traits::dispatch_convertible(source, compare_op(*this), &cvt);
}
// ----- decomposition -----
path root_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + find_root_path_size()); }
@ -1239,31 +1292,140 @@ BOOST_FORCEINLINE bool operator==(path const& lhs, path const& rhs)
return lhs.compare(rhs) == 0;
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
bool
>::type operator==(path const& lhs, Source const& rhs)
{
return lhs.compare(rhs) == 0;
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
bool
>::type operator==(Source const& lhs, path const& rhs)
{
return rhs.compare(lhs) == 0;
}
BOOST_FORCEINLINE bool operator!=(path const& lhs, path const& rhs)
{
return lhs.compare(rhs) != 0;
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
bool
>::type operator!=(path const& lhs, Source const& rhs)
{
return lhs.compare(rhs) != 0;
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
bool
>::type operator!=(Source const& lhs, path const& rhs)
{
return rhs.compare(lhs) != 0;
}
BOOST_FORCEINLINE bool operator<(path const& lhs, path const& rhs)
{
return lhs.compare(rhs) < 0;
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
bool
>::type operator<(path const& lhs, Source const& rhs)
{
return lhs.compare(rhs) < 0;
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
bool
>::type operator<(Source const& lhs, path const& rhs)
{
return rhs.compare(lhs) > 0;
}
BOOST_FORCEINLINE bool operator<=(path const& lhs, path const& rhs)
{
return !(rhs < lhs);
return lhs.compare(rhs) <= 0;
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
bool
>::type operator<=(path const& lhs, Source const& rhs)
{
return lhs.compare(rhs) <= 0;
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
bool
>::type operator<=(Source const& lhs, path const& rhs)
{
return rhs.compare(lhs) >= 0;
}
BOOST_FORCEINLINE bool operator>(path const& lhs, path const& rhs)
{
return rhs < lhs;
return lhs.compare(rhs) > 0;
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
bool
>::type operator>(path const& lhs, Source const& rhs)
{
return lhs.compare(rhs) > 0;
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
bool
>::type operator>(Source const& lhs, path const& rhs)
{
return rhs.compare(lhs) < 0;
}
BOOST_FORCEINLINE bool operator>=(path const& lhs, path const& rhs)
{
return !(lhs < rhs);
return lhs.compare(rhs) >= 0;
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
bool
>::type operator>=(path const& lhs, Source const& rhs)
{
return lhs.compare(rhs) >= 0;
}
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
bool
>::type operator>=(Source const& lhs, path const& rhs)
{
return rhs.compare(lhs) <= 0;
}
// Note: Declared as a template to delay binding to Boost.ContainerHash functions and make the dependency optional
template< typename T >
inline typename boost::enable_if_c<
@ -1294,10 +1456,7 @@ BOOST_FORCEINLINE path operator/(path lhs, path const& rhs)
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
boost::disjunction<
detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >,
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >
>::value,
detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value,
path
>::type operator/(path lhs, Source const& rhs)
{

View File

@ -187,6 +187,15 @@ typedef basic_custom_string< char > custom_string;
typedef basic_custom_string< wchar_t > wcustom_string;
typedef basic_custom_string< fs::path::value_type > pcustom_string;
inline std::string const& to_string(std::string const& s)
{
return s;
}
inline std::string to_string(fs::path const& p)
{
return p.string();
}
std::string platform(BOOST_PLATFORM);
@ -2102,6 +2111,11 @@ void construction_tests()
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
PATH_TEST_EQ(std::string_view("foo"), "foo");
#endif
// Check that path constructors don't cause ambiguity for to_string calls
// https://github.com/boostorg/filesystem/issues/273
custom_string c("test");
BOOST_TEST_EQ(to_string(c), std::string("test"));
}
// append_tests --------------------------------------------------------------------//