Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   SFINAE not applying as expected. (http://www.velocityreviews.com/forums/t955954-sfinae-not-applying-as-expected.html)

Noah Roberts 12-30-2012 02:59 AM

SFINAE not applying as expected.
 

#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::n on_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::n on_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 12-30-2012 08:43 AM

Re: SFINAE not applying as expected.
 

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.


All times are GMT. The time now is 06:55 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.