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