{
inline namespace fundamentals_v2
{
+ template<typename _Tp>
+ using __propagate_const_elem_type
+ = remove_reference_t<decltype(*std::declval<_Tp&>())>;
+
+ template<typename _Tp,
+ typename _Elem = __propagate_const_elem_type<_Tp>,
+ bool = is_convertible<const _Tp, const _Elem*>::value>
+ struct __propagate_const_conversion_c
+ { };
+
+ template<typename _Tp, typename _Elem>
+ struct __propagate_const_conversion_c<_Tp, _Elem, true>
+ {
+ constexpr operator const _Elem*() const;
+ };
+
+ template<typename _Tp,
+ typename _Elem = __propagate_const_elem_type<_Tp>,
+ bool = is_convertible<_Tp, _Elem*>::value>
+ struct __propagate_const_conversion_nc
+ { };
+
+ template<typename _Tp, typename _Elem>
+ struct __propagate_const_conversion_nc<_Tp, _Elem, true>
+ {
+ constexpr operator _Elem*();
+ };
+
+ // Base class of propagate_const<T> when T is a class type.
+ template <typename _Tp>
+ struct __propagate_const_conversions
+ : __propagate_const_conversion_c<_Tp>, __propagate_const_conversion_nc<_Tp>
+ { };
+
+ // Base class of propagate_const<T> when T is a pointer type.
+ template<typename _Tp>
+ struct __propagate_const_conversions<_Tp*>
+ {
+ constexpr operator const _Tp*() const noexcept;
+ constexpr operator _Tp*() noexcept;
+ };
+
/**
* @defgroup propagate_const Const-propagating wrapper
* @ingroup libfund-ts
/// Const-propagating wrapper.
template <typename _Tp>
- class propagate_const
+ class propagate_const : public __propagate_const_conversions<_Tp>
{
public:
- typedef remove_reference_t<decltype(*std::declval<_Tp&>())> element_type;
+ using element_type = __propagate_const_elem_type<_Tp>;
private:
template <typename _Up>
return get();
}
- template <typename _Up = _Tp,
- typename enable_if<__or_<is_pointer<_Up>,
- is_convertible<_Up,
- const element_type*>
- >::value, bool>::type = true>
- constexpr operator const element_type*() const
- {
- return get();
- }
-
constexpr const element_type& operator*() const
{
return *get();
return get();
}
- template <typename _Up = _Tp,
- typename enable_if<__or_<is_pointer<_Up>,
- is_convertible<_Up,
- const element_type*>
- >::value, bool>::type = true>
- constexpr operator element_type*()
- {
- return get();
- }
-
constexpr element_type& operator*()
{
return *get();
return __pt._M_t;
}
+ template<typename _Tp>
+ constexpr
+ __propagate_const_conversions<_Tp*>::operator const _Tp*() const noexcept
+ { return static_cast<const propagate_const<_Tp*>*>(this)->get(); }
+
+ template<typename _Tp>
+ constexpr
+ __propagate_const_conversions<_Tp*>::operator _Tp*() noexcept
+ { return static_cast<propagate_const<_Tp*>*>(this)->get(); }
+
+ template<typename _Tp, typename _Elem>
+ constexpr
+ __propagate_const_conversion_c<_Tp, _Elem, true>::
+ operator const _Elem*() const
+ { return static_cast<const propagate_const<_Tp>*>(this)->get(); }
+
+ template<typename _Tp, typename _Elem>
+ constexpr
+ __propagate_const_conversion_nc<_Tp, _Elem, true>::
+ operator _Elem*()
+ { return static_cast<propagate_const<_Tp>*>(this)->get(); }
+
/// @} group propagate_const
} // namespace fundamentals_v2
} // namespace experimental
--- /dev/null
+// { dg-do run { target c++14 } }
+
+#include <experimental/propagate_const>
+#include <testsuite_hooks.h>
+
+using std::experimental::propagate_const;
+
+void
+test_base_conversion()
+{
+ struct Base { };
+ struct Derived : Base { };
+
+ static_assert(std::is_convertible<propagate_const<Derived*>, Base*>::value,
+ "PR libstdc++/107525 - SFINAE breaks conversion operators");
+ static_assert(std::is_convertible<const propagate_const<Derived*>, const Base*>::value,
+ "PR libstdc++/107525 - SFINAE breaks conversion operators");
+}
+
+void
+test_const_conversion()
+{
+ struct X
+ {
+ int* p = nullptr;
+
+ int& operator*() const { return *p; }
+ int* operator->() const { return p; }
+ int* get() const { return p; }
+
+ operator int*() { return p; }
+ operator const int*() const = delete;
+ };
+
+ static_assert(!std::is_convertible_v<const X, const int*>,
+ "Cannot convert const X to const int*");
+ // So should not be able to convert const propagate_const<X> to const int*.
+ static_assert(!std::is_convertible_v<const propagate_const<X>, const int*>,
+ "So should not be able to convert const propagate_const<X> to "
+ "const int* (although this is not what LFTSv3 says)");
+}
+
+int main()
+{
+ test_base_conversion();
+ test_const_conversion();
+}