https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89151
Bug ID: 89151
Summary: SFINAE-disabled member hides another
Product: gcc
Version: 8.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: csaba_22 at yahoo dot co.uk
Target Milestone: ---
The following program is compiled successfully by clang-4.0, clang-6.0,
clang-trunk, GCC 7.3 (Ubuntu 7.3.0-27ubuntu1~18.04) and GCC trunk.
-------------------------------->8--------------------------------------
#include <boost/optional.hpp>
#include <string>
#if __cplusplus > 201402
#include <type_traits>
#else
namespace std {
// This indirection is needed for some older versions of GCC - including 4.8.5
(CWG 1558)
// template<typename...> using __void_t = void; // would be the natural
implementation,
// but the standard did not specify the treatment of unused arguments in an
alias template specializations,
// and GCC chose to ignore them, which makes the natural implementation
unusable.
template<typename...>
struct voider { using type = void; };
// std::void_t will be part of C++17, but until then define it ourselves:
template<typename... T>
using void_t = typename voider<T...>::type;
// void_t is "just a fancy way to spell void" (Walter E Brown)
// But *ALL* the types have to be *well formed* (that's the magic).
}
#endif
namespace detail {
// check if a type is boost::optional
template<typename T, typename = void>
struct is_boost_optional_impl : std::false_type{};
template<typename T>
struct is_boost_optional_impl<
T,
std::void_t<decltype(std::declval<T>().is_initialized())>>
: std::true_type {};
}
namespace rj_hlp {
template<typename T>
struct is_boost_optional : detail::is_boost_optional_impl<T>::type {};
}
struct get_from {
template<
typename GetWhat,
typename = typename
std::enable_if<!rj_hlp::is_boost_optional<GetWhat>::value>::type>
explicit operator GetWhat() const
{
return GetWhat{};
}
template<typename GetWhat>
explicit operator boost::optional<GetWhat> const () const
{
return boost::make_optional(GetWhat{});
}
template <typename GetWhat>
explicit operator boost::optional<GetWhat> () const
{
return this->operator boost::optional<GetWhat> const ();
}
template <typename AsWhat>
AsWhat as() const
{
return this->operator AsWhat();
}
};
struct R {
boost::optional<std::string> password;
R()
: password{ get_from().as<decltype(password)>() }
{}
};
int main()
{
R r;
}
-------------------------------->8--------------------------------------
GNU C++11 (GCC) version 8.2.0 (x86_64-pc-linux-gnu)
compiled by GNU C version 8.2.0, GMP version 6.1.2, MPFR version 4.0.1,
MPC version 1.1.0, isl version isl-0.19-GMP
reports an error:
$ g++-8.2.0 -v -Wno-class-memaccess -pipe -fsanitize=address
-fno-omit-frame-pointer -ftrapv -std=c++11 -fPIC -g -Wall -pedantic -Wextra
-Wformat=2 -Wshadow -Werror -Wmissing-include-dirs -Wuninitialized
-Wfloat-equal -Wcast-align -Wcast-qual -Wwrite-strings -Wlogical-op -O1
-Wno-error=pragmas -O0 -fstrict-aliasing -c -o bilsett.o bilsett.cc
bilsett.cc: In instantiation of ‘AsWhat get_from::as() const [with AsWhat =
boost::optional<std::__cxx11::basic_string<char> >]’:
bilsett.cc:78:48: required from here
bilsett.cc:70:32: error: no matching function for call to ‘get_from::operator
boost::optional<std::__cxx11::basic_string<char> >() const’
return this->operator AsWhat();
^
bilsett.cc:49:14: note: candidate: ‘template<class GetWhat, class>
get_from::operator GetWhat() const’
explicit operator GetWhat() const
^~~~~~~~
bilsett.cc:49:14: note: template argument deduction/substitution failed:
bilsett.cc:48:9: error: no type named ‘type’ in ‘struct std::enable_if<false,
void>’
typename = typename
std::enable_if<!rj_hlp::is_boost_optional<GetWhat>::value>::type>
^~~~~~~~
It looks as if the disabled operator GetWhat on line 49 also prevents the
compiler from using the operator GetWhat on line 55.
Boost is version 1.65.1.0ubuntu1