SFINAE not applying as expected.

Discussion in 'C++' started by Noah Roberts, Dec 30, 2012.

  1. Noah Roberts

    Noah Roberts Guest

    #include <boost/fusion/container/vector.hpp>
    #include <boost/fusion/include/at.hpp>
    #include <boost/mpl/int.hpp>
    #include <boost/tuple/tuple.hpp>

    template < int I >
    struct placeholder {};

    namespace {
    placeholder<0> a1;
    placeholder<1> a2;
    placeholder<2> a3;
    }

    template < typename ARGS
    , typename IDX >
    IDX lookup(ARGS&, IDX idx) { return idx; }

    template < typename ARGS
    , int IDX >
    typename boost::fusion::result_of::at<ARGS, boost::mpl::int_<IDX> >::type lookup(ARGS & args, placeholder<IDX>)
    {
    return boost::fusion::at_c<IDX>(args);
    }

    template < typename ARGS
    , int IDX >
    typename boost::tuples::element<IDX, ARGS>::type lookup(ARGS & args, placeholder<IDX>)
    {
    return boost::tuples::get<IDX>(args);
    }

    ..... cpp ...

    BOOST_AUTO_TEST_CASE(lookup_check)
    {
    boost::fusion::vector<int, char, std::string> args(42, 'c', "Hello");

    //BOOST_CHECK(lookup(args, 13) == 13);
    //BOOST_CHECK(lookup(args, a3) == "Hello");

    boost::tuple<int, char, std::string> args2(19, 'q', "World");
    BOOST_CHECK(lookup(args2, 88) == 88);
    BOOST_CHECK(lookup(args2, a2) == 'q');
    }


    The tuple version of course does not work with the fusion version. The fusion version results in a bunch of errors about incomplete types and such. I would expect this to be filtered out by SFINAE and use only the tuple version, but that is not happening. Why?

    Here be the error output:

    In file included from /usr/include/boost/fusion/include/at.hpp:10:0,
    from /home/nroberts/workspace/static_binder/test/../include/bind.hpp:5,
    from /home/nroberts/workspace/static_binder/test/bind_test..cpp:5:
    /usr/include/boost/fusion/sequence/intrinsic/at.hpp: In instantiation of ‘boost::fusion::result_of::at<boost::tuples::tuple<int, char, std::basic_string<char> >, mpl_::int_<1> >’:
    /home/nroberts/workspace/static_binder/test/bind_test.cpp:18:2: instantiated from here
    /usr/include/boost/fusion/sequence/intrinsic/at.hpp:56:16: error: invalid use of incomplete type ‘struct boost::fusion::extension::at_impl<boost::fusion::non_fusion_tag>::apply<boost::tuples::tuple<int, char, std::basic_string<char> >, mpl_::int_<1> >’
    /usr/include/boost/fusion/sequence/intrinsic/at.hpp:30:20: error: declaration of ‘struct boost::fusion::extension::at_impl<boost::fusion::non_fusion_tag>::apply<boost::tuples::tuple<int, char, std::basic_string<char> >, mpl_::int_<1> >’

    I know why it might not if it had made it past the signature of the function but it has not in this case. I don't understand why it isn't just aborting this function as a non-viable overload.

    Thanks.
    Noah Roberts, Dec 30, 2012
    #1
    1. Advertising

  2. Noah Roberts

    Noah Roberts Guest

    I believe I have figured out the problem. Please correct me if I'm wrong...

    SFINAE only works at the most obvious level. There's a list of valid
    deduction failures listed in 14.8.2 and if it's not among those then
    SFINAE does not apply. The failure to instantiate some template that's
    part of the template instantiation doesn't count. If I tried to access
    the type that's failing within the signature I'd get a SFINAE deduction
    failure and that function would be skipped. Unfortunately the deduction
    of the type I'm trying to create is from within another template call
    which is itself failing...and this doesn't apply.

    I tested with this code:

    typedef void (*A)();
    struct B { typedef void type; };

    template < typename T >
    struct mf { typedef typename T::type type; };

    template < typename T >
    typename T::type f(T) {}

    //template < typename T >
    //typename mf<T>::type f(T) {}

    template < typename T >
    void f(T(*)()) {}

    BOOST_AUTO_TEST_CASE(what)
    {
    f(A());
    }

    This code compiles and SFINAE applies because there's no type typename
    within the A type. But if I comment out the first f() and uncomment the
    second one (the one that uses mf), then the deduction of type depends on
    the instantiation of mf, which is what fails and this doesn't trigger
    SFINAE.
    Noah Roberts, Dec 30, 2012
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Peter Collingbourne

    problem with SFINAE applied to class methods

    Peter Collingbourne, Jul 1, 2004, in forum: C++
    Replies:
    8
    Views:
    448
    Pete Becker
    Jul 4, 2004
  2. Replies:
    3
    Views:
    1,653
    Attila Feher
    Feb 8, 2005
  3. Clark S. Cox III

    Using SFINAE with constructors

    Clark S. Cox III, Sep 9, 2005, in forum: C++
    Replies:
    2
    Views:
    368
    Howard Hinnant
    Sep 9, 2005
  4. christopher diggins

    SFINAE problem.

    christopher diggins, Sep 26, 2005, in forum: C++
    Replies:
    4
    Views:
    447
    christopher diggins
    Sep 26, 2005
  5. Aries Sun
    Replies:
    4
    Views:
    310
    Joel Yliluoma
    Nov 29, 2007
Loading...

Share This Page