Re: [Boost-users] [Concepts & EnableIf] Is void special?

19 views
Skip to first unread message

Robert Jones

unread,
Mar 28, 2012, 3:42:32 AM3/28/12
to boost...@lists.boost.org
On Tue, Mar 27, 2012 at 8:21 PM, Jeremiah Willcock <jewi...@osl.iu.edu> wrote:
On Tue, 27 Mar 2012, Robert Jones wrote:

On Tue, Mar 27, 2012 at 5:02 PM, Jeremiah Willcock <jewi...@osl.iu.edu> wrote:
     On Tue, 27 Mar 2012, Robert Jones wrote:

           Hi Peeps
           Can anyone cast any light on this...

           I want to write function which accepts a single pass range of X's, so something like this

           struct X { };

           template <typename T>
               BOOST_CONCEPT_REQUIRES(
                   (( boost::SinglePassRangeConcept<T> )),
                   ( typename boost::enable_if<boost::is_same<typename boost::range_value<T>::type, X>, void>::type ))
               my_function( const T & range );

           Is that a reasonable construction, or is there a better way to say it?

           Next, it doesn't seem to work. It does seem to work if the type to which enable_if resolves is anything
           except void, but not for void. Why is this?


Does it only fail if you try to pass something in that is not a range? I'm not sure that BOOST_CONCEPT_REQUIRES does SFINAE, but if it does, you will need a
metafunction (and possibly lazy_enable_if) to avoid accessing range_value<T> when T is not a range if that doesn't instantiate properly for non-ranges.

No, it fails when the parameter IS a valid range, of the required value type. I can create the same effect by
substituting void for the whole enable_if bit, and then using BOOST_ASSERT in the body of the function to impose
the same condition, but that is obviously less satisfactory.

I suspect void is special because it is enable_if's returned type if type is not specified, but I can't quite see why, or
what the impact of that is.

Does it still fail even if you don't use BOOST_CONCEPT_REQUIRES?  If the function fails only with a void return type, are you sure you're not trying to return something (at least along some control flow path)?  What in particular is the error message you get?


No. I can use the enable_if part without the BOOST_CONCEPT_REQUIRES and it's fine. I can use the BOOST_CONCEPT_REQUIRES bit and then use a simple void
in place of the enable_if and that's fine too. Together, not fine! I'm going to take a little time to construct a minimal self contained example.

Thx, Rob.
 

Robert Jones

unread,
Mar 28, 2012, 4:57:30 AM3/28/12
to boost...@lists.boost.org
Hi All

Ok, I should probably have started this thread with this self contained code example.

What's wrong with this?


#include <vector>
#include <boost/concept/requires.hpp>
#include <boost/range/concepts.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>

template <typename T>
    BOOST_CONCEPT_REQUIRES(
            (( boost::SinglePassRangeConcept<T> )),
//             ( void ))
            ( typename boost::enable_if<boost::is_same<typename boost::range_value<T>::type, int>, void>::type ))
    f( const T & ) { }

int main( )
{
    std::vector<int> v;
    f( v );
}

g++    -c -o enable_if.o enable_if.cpp
enable_if.cpp: In function ‘int main()’:
enable_if.cpp:17: error: no matching function for call to ‘f(std::vector<int, std::allocator<int> >&)’

If I comment out the enable_if line and comment in the void line it's fine.

TIA, Rob.

Jeremiah Willcock

unread,
Mar 28, 2012, 11:24:50 AM3/28/12
to boost...@lists.boost.org
On Wed, 28 Mar 2012, Robert Jones wrote:

> Hi All
>
> Ok, I should probably have started this thread with this self contained code example.
>
> What's wrong with this?
>
>
> #include <vector>
> #include <boost/concept/requires.hpp>
> #include <boost/range/concepts.hpp>
> #include <boost/utility/enable_if.hpp>
> #include <boost/type_traits/is_same.hpp>
>
> template <typename T>

> � � BOOST_CONCEPT_REQUIRES(
> � � � � � � (( boost::SinglePassRangeConcept<T> )),
> // � � � � � � ( void ))
> � � � � � � ( typename boost::enable_if<boost::is_same<typename boost::range_value<T>::type, int>, void>::type ))
> � � f( const T & ) { }
>
> int main( )
> {
> � � std::vector<int> v;
> � � f( v );
> }
>
> g++ � �-c -o enable_if.o enable_if.cpp
> enable_if.cpp: In function �int main()�:
> enable_if.cpp:17: error: no matching function for call to �f(std::vector<int, std::allocator<int> >&)�


>
> If I comment out the enable_if line and comment in the void line it's fine.

It looks like the trick is to put the enable_if outside the
BOOST_CONCEPT_REQUIRES, as in:

template <typename T>
typename enable_if<
condition,
BOOST_CONCEPT_REQUIRES(concept, (void))>::type

Paragraph 4 of [dcl.fct] (in the latest draft) seems to say that the
SFINAE error you are getting is required: only the specific type void,
written in a non-dependent way, counts as a valid function parameter type.

-- Jeremiah Willcock

Robert Jones

unread,
Mar 28, 2012, 12:22:21 PM3/28/12
to boost...@lists.boost.org
On Wed, Mar 28, 2012 at 4:24 PM, Jeremiah Willcock <jewi...@osl.iu.edu> wrote:

It looks like the trick is to put the enable_if outside the BOOST_CONCEPT_REQUIRES, as in:

template <typename T>
typename enable_if<
          condition,
          BOOST_CONCEPT_REQUIRES(concept, (void))>::type

Paragraph 4 of [dcl.fct] (in the latest draft) seems to say that the SFINAE error you are getting is required: only the specific type void, written in a non-dependent way, counts as a valid function parameter type.


Well, I can't deny that it works! Seems to be reading quite a bit into the standard tho', assuming you're looking at


If I'm reading it right it is actually talking about function parameter lists, rather than function return types, and stating that
void is not a valid parameter type except for f(void) to indicate an empty parameter list.

Thx, Rob.

Jeremiah Willcock

unread,
Mar 28, 2012, 1:09:48 PM3/28/12
to boost...@lists.boost.org
On Wed, 28 Mar 2012, Robert Jones wrote:

The internals of BOOST_CONCEPT_REQUIRES take the type that you give as the
return type and use it as a function parameter type (that is why you need
the parentheses around the outside). That is where those rules in the
standard get involved.

-- Jeremiah Willcock

Robert Jones

unread,
Mar 28, 2012, 3:37:57 PM3/28/12
to boost...@lists.boost.org
Ah, thank you, clears it up nicely. I can sleep peacefully!

- Rob.
 

Dave Abrahams

unread,
Mar 30, 2012, 9:43:33 PM3/30/12
to boost...@lists.boost.org

on Tue Mar 27 2012, Jeremiah Willcock <jewillco-AT-osl.iu.edu> wrote:

> On Tue, 27 Mar 2012, Robert Jones wrote:
>
>> Hi Peeps
>> Can anyone cast any light on this...
>>
>> I want to write function which accepts a single pass range of X's, so something like this
>>
>> struct X { };
>>
>> template <typename T>
>>     BOOST_CONCEPT_REQUIRES(

>>         (( boost::SinglePassRangeConcept<T> )),

>>         ( typename boost::enable_if<boost::is_same<typename

>> boost::range_value<T>::type, X>, void>::type ))
>>     my_function( const T & range );
>>
>> Is that a reasonable construction, or is there a better way to say it?
>>
>> Next, it doesn't seem to work. It does seem to work if the type to
>> which enable_if resolves is anything
>> except void, but not for void. Why is this?
>
> Does it only fail if you try to pass something in that is not a range?
> I'm not sure that BOOST_CONCEPT_REQUIRES does SFINAE, but if it does,

It doesn't.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Reply all
Reply to author
Forward
0 new messages