Opened 8 years ago

Last modified 5 years ago

#9953 new Feature Requests

lazy_enable_if is not sfinae friendly

Reported by: hui.li@… Owned by: Peter Dimov
Milestone: To Be Determined Component: core
Version: Boost 1.55.0 Severity: Problem
Keywords: Cc:

Description

The following code fails to compile, even though boost::result_of itself is sfinae friendly.

template < typename T >
typename boost::lazy_enable_if_c<
  boost::is_class<T>::value,
  boost::result_of<T(int)>
>::type
test(int){}

template < typename >
void test(...) {}

struct A{}; // boost::result_of<A(int)> is a valid type that doesn't have a member called "type"

int main(int argc, const char * argv[])
{
  test<A>(0); // test<A>(int) meant to be a substitution failure
  return 0;
}

I'm not sure if this is a bug/flaw, or a lack of feature, or maybe this kind of use is deliberately disallowed for some reason, but it could be very useful if lazy_enable_if_c<bool B, typename T> etc support uses when typename T::type itself may cause a substitution failure.

Proposing to change implementation of lazy_enable_if_c and lazy_disable_if_c to:

template <bool B, class T>
struct lazy_enable_if_c : T {}; // inherits from T

template <class T>
struct lazy_enable_if_c<false, T> {};

template <bool B, class T = void>
struct disable_if_c : T {};  // inherits from T

template <class T>
struct disable_if_c<true, T> {};

Change History (2)

comment:1 by anonymous, 8 years ago

I should mention what error i get when compiling the test code. On clang++-3.4 with -std=c++11, I got:

clang++-mp-3.4 -std=c++11 -I /opt/local/include/ main.cpp 
In file included from main.cpp:1:
In file included from /opt/local/include/boost/type_traits.hpp:65:
In file included from /opt/local/include/boost/type_traits/is_nothrow_move_assignable.hpp:22:
/opt/local/include/boost/utility/enable_if.hpp:40:25: error: no type named 'type' in 'boost::result_of<A (int)>'
   typedef typename T::type type;
           ~~~~~~~~~~~~^~~~
main.cpp:12:1: note: in instantiation of template class 'boost::lazy_enable_if_c<true, boost::result_of<A (int)> >'
     requested here
typename boost::lazy_enable_if_c<
^
main.cpp:16:1: note: while substituting explicitly-specified template arguments into function template 'test'
test(int){}
^
1 error generated.

comment:2 by Andrey Semashev, 5 years ago

Component: utilitycore
Owner: changed from No-Maintainer to Peter Dimov

This might be useful. Deriving from T won't work if it is final, but in C++11 we could reformulate lazy_enable_if_c like this:

template< bool Cond, typename T >
using lazy_enable_if_c = typename enable_if_c< Cond, T >::type::type;
Note: See TracTickets for help on using tickets.