New, powerful way to use enable_if in C++0x

I'm not sure if there is much interest in this or if someone else discovered this as well, but I realized today that enable_if can be used in a new way in C++0x. Traditionally when working with enable_if with function templates you invoke it either in the return type or in an additional function parameter of the function. Each of these has advantages and disadvantages. The parameter form has the downside of augmenting the parameter list. The most notable problems with this approach are that it can't be used with overloaded operators that require a fixed number of arguments, and it can't be used after a variadic argument list. The return type use of enable_if is often preferred since it does not involve augmenting the parameter list, meaning that it can be used with most overloaded operators, but you still can't use it for conversion operations and you can't use it all with constructors as they have no explicit return type. However, in C++0x, there is a new way to use enable_if by altering neither the function parameter list nor the specification of the return type. It can be used with operators, constructors, variadic function templates, and even overloaded conversion operations (the latter of which was previously considered impossible). The way to do it is with C++0x default function template parameters. Rather than try to explain any further in English, the following code should demonstrate the approach fairly clearly (tested in GCC 4.5.2): http://codepaste.net/23yo8o There is only one drawback that I can think of off of the top of my head -- you can't refer to the function parameters by name for the enable_if condition, whereas in C++0x if you use the return type form of enable_if along with the new trailing return type form of function declarations you can. I have never personally wanted to do this and I highly doubt that it's common so this is likely entirely a non-issue, plus you can always use std::declval anyway so you aren't actually losing any high-level functionality. Are there any thoughts on this or drawbacks other than what I mentioned? Should such use be added to the docs as supported behavior in 0x compilers? -- -Matt Calabrese

On Mon, Apr 11, 2011 at 2:15 PM, Matt Calabrese <rivorus@gmail.com> wrote:
I'm not sure if there is much interest in this or if someone else discovered this as well, but I realized today that enable_if can be used in a new way in C++0x. Traditionally when working with enable_if with function templates you invoke it either in the return type or in an additional function parameter of the function. Each of these has advantages and disadvantages.
The parameter form has the downside of augmenting the parameter list. The most notable problems with this approach are that it can't be used with overloaded operators that require a fixed number of arguments, and it can't be used after a variadic argument list.
The return type use of enable_if is often preferred since it does not involve augmenting the parameter list, meaning that it can be used with most overloaded operators, but you still can't use it for conversion operations and you can't use it all with constructors as they have no explicit return type.
However, in C++0x, there is a new way to use enable_if by altering neither the function parameter list nor the specification of the return type. It can be used with operators, constructors, variadic function templates, and even overloaded conversion operations (the latter of which was previously considered impossible). The way to do it is with C++0x default function template parameters.
Rather than try to explain any further in English, the following code should demonstrate the approach fairly clearly (tested in GCC 4.5.2): http://codepaste.net/23yo8o
There is only one drawback that I can think of off of the top of my head -- you can't refer to the function parameters by name for the enable_if condition, whereas in C++0x if you use the return type form of enable_if along with the new trailing return type form of function declarations you can. I have never personally wanted to do this and I highly doubt that it's common so this is likely entirely a non-issue, plus you can always use std::declval anyway so you aren't actually losing any high-level functionality. Are there any thoughts on this or drawbacks other than what I mentioned? Should such use be added to the docs as supported behavior in 0x compilers?
Thanks! I have an immediate use for this technique! -- Stirling Westrup Programmer, Entrepreneur. https://www.linkedin.com/e/fpf/77228 http://www.linkedin.com/in/swestrup http://technaut.livejournal.com http://sourceforge.net/users/stirlingwestrup

On Mon, Apr 11, 2011 at 11:15 AM, Matt Calabrese <rivorus@gmail.com> wrote:
I'm not sure if there is much interest in this or if someone else discovered this as well, but I realized today that enable_if can be used in a new way in C++0x. Traditionally when working with enable_if with function templates you invoke it either in the return type or in an additional function parameter of the function. Each of these has advantages and disadvantages.
The parameter form has the downside of augmenting the parameter list. The most notable problems with this approach are that it can't be used with overloaded operators that require a fixed number of arguments, and it can't be used after a variadic argument list.
The return type use of enable_if is often preferred since it does not involve augmenting the parameter list, meaning that it can be used with most overloaded operators, but you still can't use it for conversion operations and you can't use it all with constructors as they have no explicit return type.
However, in C++0x, there is a new way to use enable_if by altering neither the function parameter list nor the specification of the return type. It can be used with operators, constructors, variadic function templates, and even overloaded conversion operations (the latter of which was previously considered impossible). The way to do it is with C++0x default function template parameters.
Rather than try to explain any further in English, the following code should demonstrate the approach fairly clearly (tested in GCC 4.5.2): http://codepaste.net/23yo8o
There is only one drawback that I can think of off of the top of my head -- you can't refer to the function parameters by name for the enable_if condition, whereas in C++0x if you use the return type form of enable_if along with the new trailing return type form of function declarations you can. I have never personally wanted to do this and I highly doubt that it's common so this is likely entirely a non-issue, plus you can always use std::declval anyway so you aren't actually losing any high-level functionality. Are there any thoughts on this or drawbacks other than what I mentioned? Should such use be added to the docs as supported behavior in 0x compilers?
I think the case for conversion operators alone is compelling enough to warrant this use being mentioned in the Boost.EnableIf docs... - Jeff

AMDG On 04/11/2011 11:40 AM, Jeffrey Lee Hellrung, Jr. wrote:
On Mon, Apr 11, 2011 at 11:15 AM, Matt Calabrese<rivorus@gmail.com> wrote:
However, in C++0x, there is a new way to use enable_if by altering neither the function parameter list nor the specification of the return type. It can be used with operators, constructors, variadic function templates, and even overloaded conversion operations (the latter of which was previously considered impossible). The way to do it is with C++0x default function template parameters.
<snip> Should such use be added to the docs as supported behavior in 0x compilers?
I think the case for conversion operators alone is compelling enough to warrant this use being mentioned in the Boost.EnableIf docs...
I agree. Matt, how about making a patch for the docs? In Christ, Steven Watanabe

On Mon, Apr 11, 2011 at 5:38 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
On 04/11/2011 11:40 AM, Jeffrey Lee Hellrung, Jr. wrote:
On Mon, Apr 11, 2011 at 11:15 AM, Matt Calabrese<rivorus@gmail.com> wrote:
However, in C++0x, there is a new way to use enable_if by altering neither the function parameter list nor the specification of the return type. It can be used with operators, constructors, variadic function templates, and even overloaded conversion operations (the latter of which was previously considered impossible). The way to do it is with C++0x default function template parameters.
<snip> Should such use be added to the docs as supported behavior in 0x compilers?
I think the case for conversion operators alone is compelling enough to warrant this use being mentioned in the Boost.EnableIf docs...
I agree. Matt, how about making a patch for the docs?
+1 This is seriously slick, and needs to be added to the enable_if docs as soon as possible. The example code is a model of clarity, IMO, and should also become part of the docs. --Beman

On Mon, 11 Apr 2011, Beman Dawes wrote:
On Mon, Apr 11, 2011 at 5:38 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
On 04/11/2011 11:40 AM, Jeffrey Lee Hellrung, Jr. wrote:
On Mon, Apr 11, 2011 at 11:15 AM, Matt Calabrese<rivorus@gmail.com> wrote:
However, in C++0x, there is a new way to use enable_if by altering neither the function parameter list nor the specification of the return type. It can be used with operators, constructors, variadic function templates, and even overloaded conversion operations (the latter of which was previously considered impossible). The way to do it is with C++0x default function template parameters.
<snip> Should such use be added to the docs as supported behavior in 0x compilers?
I think the case for conversion operators alone is compelling enough to warrant this use being mentioned in the Boost.EnableIf docs...
I agree. Matt, how about making a patch for the docs?
+1
This is seriously slick, and needs to be added to the enable_if docs as soon as possible.
The example code is a model of clarity, IMO, and should also become part of the docs.
I will apply a patch if someone sends one. -- Jeremiah Willcock

On 4/11/2011 7:01 PM, Matt Calabrese wrote:
On Mon, Apr 11, 2011 at 9:57 PM, Jeremiah Willcock<jewillco@osl.iu.edu>wrote:
I will apply a patch if someone sends one.
-- Jeremiah Willcock
Making one right now.
Might I suggest some mention of which compilers currently support this method, or at least the necessary pieces of C++0x which it uses?

Matt Calabrese wrote:
I'm not sure if there is much interest in this or if someone else discovered this as well, but I realized today that enable_if can be used in a new way in C++0x. Traditionally when working with enable_if with function templates you invoke it either in the return type or in an additional function parameter of the function. Each of these has advantages and disadvantages.
The parameter form has the downside of augmenting the parameter list. The most notable problems with this approach are that it can't be used with overloaded operators that require a fixed number of arguments, and it can't be used after a variadic argument list.
The return type use of enable_if is often preferred since it does not involve augmenting the parameter list, meaning that it can be used with most overloaded operators, but you still can't use it for conversion operations and you can't use it all with constructors as they have no explicit return type.
However, in C++0x, there is a new way to use enable_if by altering neither the function parameter list nor the specification of the return type. It can be used with operators, constructors, variadic function templates, and even overloaded conversion operations (the latter of which was previously considered impossible). The way to do it is with C++0x default function template parameters.
Rather than try to explain any further in English, the following code should demonstrate the approach fairly clearly (tested in GCC 4.5.2): http://codepaste.net/23yo8o
There is only one drawback that I can think of off of the top of my head -- you can't refer to the function parameters by name for the enable_if condition, whereas in C++0x if you use the return type form of enable_if along with the new trailing return type form of function declarations you can. I have never personally wanted to do this and I highly doubt that it's common so this is likely entirely a non-issue, plus you can always use std::declval anyway so you aren't actually losing any high-level functionality. Are there any thoughts on this or drawbacks other than what I mentioned? Should such use be added to the docs as supported behavior in 0x compilers?
Nice! The idea is very useful and powerful indeed, and one I'd definitely like to see documented. I have a question however. Is there a particular reason you did it like: typename boost::enable_if< boost::is_arithmetic< T > >::type*& = boost::enabler instead of: typename Enable = typename boost::enable_if< boost::is_arithmetic< T > >::type ? The latter seems clearer to me and removes the need to introduce a boost::enabler identifier. Thank you! Best Regards, Gevorg

On Mon, Apr 11, 2011 at 3:34 PM, Gevorg Voskanyan <v_gevorg@yahoo.com>wrote:
Nice! The idea is very useful and powerful indeed, and one I'd definitely like to see documented. I have a question however. Is there a particular reason you did it like: typename boost::enable_if< boost::is_arithmetic< T > >::type*& = boost::enabler instead of: typename Enable = typename boost::enable_if< boost::is_arithmetic< T >
::type ? The latter seems clearer to me and removes the need to introduce a boost::enabler identifier.
It's necessary because otherwise with two overloads you'd end up with two declarations that differ only in default arguments, which would be a compile error. For instance, consider the following: ////////// template< class T, class Enable = typename enable_if< is_arithmetic< T >
::type > void foo( T ) {}
template< class T, class Enable = typename enable_if< is_pointer< T >
::type > void foo( T ) {} //////////
This would be an error even though the conditions don't overlap! To better understand why, imagine it with the defaults removed. Both of them are actually declaring exactly the same function template with the only difference being that they use a different default. In other words both are declaring: ////////// template< class T, class Enable > void foo( T ); ////////// however, you have provided two different defaults and two different definitions. This is, of course, an error. If the fact that they're templates is throwing you off, compare this to regular function argument defaults: ////////// void bar( int arg = 5 ) {} void bar( int arg = 6 ) {} ////////// This code has a similar problem to the code you posted above. Even though the defaults are different, they are still just declaring void bar( int ); The fact that we are exploiting SFINAE with the default argument in the template example does not change that. We have to make substitution fail when forming template parameter type itself as opposed to just its default. -- -Matt Calabrese

2011/4/11 Matt Calabrese <rivorus@gmail.com>
On Mon, Apr 11, 2011 at 3:34 PM, Gevorg Voskanyan <v_gevorg@yahoo.com
wrote:
Nice! The idea is very useful and powerful indeed, and one I'd definitely like to see documented. I have a question however. Is there a particular reason you did it like: typename boost::enable_if< boost::is_arithmetic< T > >::type*& = boost::enabler instead of: typename Enable = typename boost::enable_if< boost::is_arithmetic< T >
::type ? The latter seems clearer to me and removes the need to introduce a boost::enabler identifier.
It's necessary because otherwise with two overloads you'd end up with two declarations that differ only in default arguments, which would be a compile error. For instance, consider the following:
////////// template< class T, class Enable = typename enable_if< is_arithmetic< T >
::type > void foo( T ) {}
template< class T, class Enable = typename enable_if< is_pointer< T >
::type > void foo( T ) {} //////////
This would be an error even though the conditions don't overlap! To better understand why, imagine it with the defaults removed. Both of them are actually declaring exactly the same function template with the only difference being that they use a different default. In other words both are declaring:
////////// template< class T, class Enable > void foo( T ); //////////
however, you have provided two different defaults and two different definitions. This is, of course, an error.
If the fact that they're templates is throwing you off, compare this to regular function argument defaults:
////////// void bar( int arg = 5 ) {} void bar( int arg = 6 ) {} //////////
This code has a similar problem to the code you posted above. Even though the defaults are different, they are still just declaring void bar( int ); The fact that we are exploiting SFINAE with the default argument in the template example does not change that. We have to make substitution fail when forming template parameter type itself as opposed to just its default.
I love this! ;-) Another drawback is the necesicy to use the typename keyword, which suggests at first glance, that this is a type template parameter, while it actually is a constant template parameter. The fact, that boost::enabler is hidden from user view, so the user can't see it isn't a type, doesn't help. For an alternative without boost::enabler, how about: typename boost::enable_if< boost::is_arithmetic<T>, int >::type = 0 Regards Kris

On Mon, Apr 11, 2011 at 5:07 PM, Krzysztof Czainski <1czajnik@gmail.com>wrote:
I love this! ;-)
Another drawback is the necesicy to use the typename keyword, which suggests at first glance, that this is a type template parameter, while it actually is a constant template parameter. The fact, that boost::enabler is hidden from user view, so the user can't see it isn't a type, doesn't help.
For an alternative without boost::enabler, how about: typename boost::enable_if< boost::is_arithmetic<T>, int >::type = 0
Regards Kris
That's good too. I guess whoever maintains boost.Enable_If could make the call as to what to suggest. The only thing I kind of like about the boost::enabler version is that it's extremely unlikely that it would conflict with another template declaration as pretty much no one ever uses void*& template parameter types in practice. It is rather odd to see though. -- -Matt Calabrese

Matt Calabrese wrote:
Gevorg Voskanyan wrote:
Is there a particular reason you did it like: typename boost::enable_if< boost::is_arithmetic< T > >::type*& = boost::enabler instead of: typename Enable = typename boost::enable_if< boost::is_arithmetic< T >
::type ? The latter seems clearer to me and removes the need to introduce a boost::enabler identifier.
It's necessary because otherwise with two overloads you'd end up with two declarations that differ only in default arguments, which would be a compile error.
Yes, of course that's very true, I wonder how could I miss that! This could be included in the rationale section of the doc to prevent other users from being tempted to "simplify" it as I was. :) [snip] Thanks, Gevorg

On Mon, Apr 11, 2011 at 5:16 PM, Gevorg Voskanyan <v_gevorg@yahoo.com>wrote:
Yes, of course that's very true, I wonder how could I miss that! This could be included in the rationale section of the doc to prevent other users from being tempted to "simplify" it as I was. :)
For what it's worth, I missed it too! My first approach prior to the boost::enabler version was exactly as you described and I didn't realize the problem until I tested it, so yeah, rationale here is probably important. It is very subtle. -- -Matt Calabrese

Message du 11/04/11 20:16 De : "Matt Calabrese" A : boost@lists.boost.org Copie à : Objet : [boost] New, powerful way to use enable_if in C++0x
I'm not sure if there is much interest in this or if someone else discovered this as well, but I realized today that enable_if can be used in a new way in C++0x. Traditionally when working with enable_if with function templates you invoke it either in the return type or in an additional function parameter of the function. Each of these has advantages and disadvantages.
The parameter form has the downside of augmenting the parameter list. The most notable problems with this approach are that it can't be used with overloaded operators that require a fixed number of arguments, and it can't be used after a variadic argument list.
The return type use of enable_if is often preferred since it does not involve augmenting the parameter list, meaning that it can be used with most overloaded operators, but you still can't use it for conversion operations and you can't use it all with constructors as they have no explicit return type.
However, in C++0x, there is a new way to use enable_if by altering neither the function parameter list nor the specification of the return type. It can be used with operators, constructors, variadic function templates, and even overloaded conversion operations (the latter of which was previously considered impossible). The way to do it is with C++0x default function template parameters.
Rather than try to explain any further in English, the following code should demonstrate the approach fairly clearly (tested in GCC 4.5.2): http://codepaste.net/23yo8o
I like what you are trying to achieve, the fact that we could constraint the conversion operators and also the fact that the template parameter constraints are closer to the template parameters. There is yet another advantage in my opinion: the use of enable_is can be done in a uniform way for all the templates, classes or functions.
There is only one drawback that I can think of off of the top of my head -- you can't refer to the function parameters by name for the enable_if condition, whereas in C++0x if you use the return type form of enable_if along with the new trailing return type form of function declarations you can. I have never personally wanted to do this and I highly doubt that it's common so this is likely entirely a non-issue, plus you can always use std::declval anyway so you aren't actually losing any high-level functionality. Are there any thoughts on this or drawbacks other than what I mentioned? Should such use be added to the docs as supported behavior in 0x compilers?
I expected that this technique could not be used with variadic templates, but I see that you have used it in one of the examples. Thanks Mat for sharing this with us, Vicente

Matt Calabrese wrote:
I realized today that enable_if can be used in a new way in C++0x.
This is very slick, as so many have noted already. However, I wonder if you couldn't repackage your idea in, say, enable_when and disable_when (plus variants) so that the usage is slightly simpler: class test { template < class... T , typename boost::enable_when_c<sizeof...(T) == 10>::type = true
test(T &&...); }; IOW, enable_when_c would expose a nested type, type, of type bool that makes forming the default easy[*]. You could use a pointer or integer type and default to 0, for example, but expressing the default as "= true" just looks good and is easy to remember. enable_when can derive from enable_if, reusing that machinery with your void *& trick, but hiding it from normal use as shown above. enable_when only needs one template argument, too, as there's no need for overriding the type of the nested type. [*] I was wondering if I could fit "type" any more times in that sentence, especially in close proximity to the three it already contains! _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

2011/4/12 Stewart, Robert <Robert.Stewart@sig.com>
Matt Calabrese wrote:
I realized today that enable_if can be used in a new way in C++0x.
This is very slick, as so many have noted already. However, I wonder if you couldn't repackage your idea in, say, enable_when and disable_when (plus variants) so that the usage is slightly simpler:
class test { template < class... T , typename boost::enable_when_c<sizeof...(T) == 10>::type = true
test(T &&...); };
IOW, enable_when_c would expose a nested type, type, of type bool that makes forming the default easy[*]. You could use a pointer or integer type and default to 0, for example, but expressing the default as "= true" just looks good and is easy to remember.
Enable_when looks good to me, except for one detail: "enable_when< [...]
::type = true" may confuse someone, that "enable_when< [...] >::type = false" is a synonym for "disable_when< [...] >::type = true", so I'm be against the part "= true". I'd most like it to be "= 0", but "= boost::enabler" looks ok to me too.
Regards, Kris

Krzysztof Czainski wrote:
2011/4/12 Stewart, Robert <Robert.Stewart@sig.com>
I wonder if you couldn't repackage your idea in, say, enable_when and disable_when (plus variants) so that the usage is slightly simpler:
class test { template < class... T , typename boost::enable_when_c<sizeof...(T) == 10>::type = true
test(T &&...); };
IOW, enable_when_c would expose a nested type, type, of type bool that makes forming the default easy[*]. You could use a pointer or integer type and default to 0, for example, but expressing the default as "= true" just looks good and is easy to remember.
Enable_when looks good to me, except for one detail: "enable_when< [...] >::type = true" may confuse someone, that "enable_when< [...] >::type = false" is a synonym for "disable_when< [...] >::type = true", so I'm be against the part "= true". I'd most like it to be "= 0", but "= boost::enabler" looks ok to me too.
I thought about the "= false" issue, but not from the perspective of someone thinking it would negate the logic. We can document that the convention is to use "= true", but that "= false" has the same effect but with less clarity. I really doubt anyone would choose "= false" unless they thought it would negate the logic. Still, I think documentation can prevent that misuse by virtue of a stern warning. "= 0" would also work, if the type is a pointer or integer type, but other pointer or integer values can then be used, so they really aren't different than true/false. (Actually, "= 0" would work if the type were bool, too.) Non-zero values might be thought of as normal, and zero values as negated, logic, thus leading to the same concerns as for bool. I don't care for boost::enabler because "boost::" and "enable" are repeated (the first "enable" is in "enable_when") and a long line is made even longer. Note that the use of boost::enabler is optional: the type is void *&, so, for example, "= 0" works just as well and might be thought to negate enable_when. If enable_when/disable_when were to use a pointer to a UDT and boost::enabler were a pointer of that type, then that might be the only convenient value aside from zero, but that doesn't avoid the possible confusion as with each of the other options. The only ways I can think of to force one default value is with an enumerated type or a UDT with a member the address of which must be supplied. The latter requires that the member have external linkage, so the former is simpler: namespace boost { enum enabler { is_true }; // some clear, short, non-clashing name } boost::enable_when<...>::type = boost::is_true That would use enable_if<...,enabler>::type, of course. _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On Tue, Apr 12, 2011 at 6:00 AM, Stewart, Robert <Robert.Stewart@sig.com>wrote:
Krzysztof Czainski wrote:
2011/4/12 Stewart, Robert <Robert.Stewart@sig.com>
I wonder if you couldn't repackage your idea in, say, enable_when and disable_when (plus variants) so that the usage is slightly simpler:
class test { template < class... T , typename boost::enable_when_c<sizeof...(T) == 10>::type = true
test(T &&...); };
IOW, enable_when_c would expose a nested type, type, of type bool that makes forming the default easy[*]. You could use a pointer or integer type and default to 0, for example, but expressing the default as "= true" just looks good and is easy to remember.
Enable_when looks good to me, except for one detail: "enable_when< [...] >::type = true" may confuse someone, that "enable_when< [...] >::type = false" is a synonym for "disable_when< [...] >::type = true", so I'm be against the part "= true". I'd most like it to be "= 0", but "= boost::enabler" looks ok to me too.
I thought about the "= false" issue, but not from the perspective of someone thinking it would negate the logic. We can document that the convention is to use "= true", but that "= false" has the same effect but with less clarity. I really doubt anyone would choose "= false" unless they thought it would negate the logic. Still, I think documentation can prevent that misuse by virtue of a stern warning.
"= 0" would also work, if the type is a pointer or integer type, but other pointer or integer values can then be used, so they really aren't different than true/false. (Actually, "= 0" would work if the type were bool, too.) Non-zero values might be thought of as normal, and zero values as negated, logic, thus leading to the same concerns as for bool.
I don't care for boost::enabler because "boost::" and "enable" are repeated (the first "enable" is in "enable_when") and a long line is made even longer. Note that the use of boost::enabler is optional: the type is void *&, so, for example, "= 0" works just as well and might be thought to negate enable_when.
If enable_when/disable_when were to use a pointer to a UDT and boost::enabler were a pointer of that type, then that might be the only convenient value aside from zero, but that doesn't avoid the possible confusion as with each of the other options.
The only ways I can think of to force one default value is with an enumerated type or a UDT with a member the address of which must be supplied. The latter requires that the member have external linkage, so the former is simpler:
namespace boost { enum enabler { is_true }; // some clear, short, non-clashing name }
boost::enable_when<...>::type = boost::is_true
That would use enable_if<...,enabler>::type, of course.
Ease-of-use and conciseness are certainly concerns, but might I suggest: don't add anything yet to the Boost.EnableIf library, just update the documentation to mention the use of Boost.EnableIf in defaulted template parameters (perhaps in all the different styles mentioned above), and see if anything close to idiomatic settles in. Unless, I guess, there's broad consensus on the list regarding a particular style... - Jeff

On Tue, Apr 12, 2011 at 10:10 AM, Jeffrey Lee Hellrung, Jr. < jeffrey.hellrung@gmail.com> wrote:
Ease-of-use and conciseness are certainly concerns, but might I suggest: don't add anything yet to the Boost.EnableIf library, just update the documentation to mention the use of Boost.EnableIf in defaulted template parameters (perhaps in all the different styles mentioned above), and see if anything close to idiomatic settles in. Unless, I guess, there's broad consensus on the list regarding a particular style...
I'm just updating it with the int version that Kris suggested a while back for now, since it doesn't involve changes to any code, just docs. -- -Matt Calabrese

On Tue, Apr 12, 2011 at 9:00 AM, Stewart, Robert <Robert.Stewart@sig.com>wrote:
I don't care for boost::enabler because "boost::" and "enable" are repeated (the first "enable" is in "enable_when") and a long line is made even longer. Note that the use of boost::enabler is optional: the type is void *&, so, for example, "= 0" works just as well and might be thought to negate enable_when.
You can't initialize a reference template parameter to 0 (I don't believe you can for pointer parameters either for that matter). If we go the route of making _when templates (which I'm not sure is a great idea as it doubles the number of templates in Boost.Enable_If), the syntax that I think would be best would be: typename enable_when< is_arithmetic< T > >::type = {} where ::type would refer to a detail enum, but unfortunately {} doesn't seem to be a valid default for a template parameter. Does anyone know the rationale for this offhand? I don't immediately see a problem with it. I haven't looked at the standard but Comeau doesn't allow such defaults either so I assume it's not just a broken implementation. -- -Matt Calabrese

Matt Calabrese wrote:
On Tue, Apr 12, 2011 at 9:00 AM, Stewart, Robert <Robert.Stewart@sig.com>wrote:
I don't care for boost::enabler because "boost::" and "enable" are repeated (the first "enable" is in "enable_when") and a long line is made even longer. Note that the use of boost::enabler is optional: the type is void *&, so, for example, "= 0" works just as well and might be thought to negate enable_when.
You can't initialize a reference template parameter to 0 (I don't believe you can for pointer parameters either for that matter).
You're right regarding references, of course, but a pointer to const should allow initialization from 0, right?
If we go the route of making _when templates (which I'm not sure is a great idea as it doubles the number of templates in Boost.Enable_If),
That's a minor issue, compared to *& on the end which, as you noted previously, is unusual, and is easy to forget. Consider the error messages if one forgets to add *&.
the syntax that I think would be best would be:
typename enable_when< is_arithmetic< T > >::type = {}
Interesting, but not nearly as clear as "= true." OTOH, it eliminates the *& line noise. Since I don't have access to a C++11 compiler that supports default function template arguments, I can't offer any other concrete suggestions. _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On Tue, Apr 12, 2011 at 12:56 PM, Stewart, Robert <Robert.Stewart@sig.com>wrote:
That's a minor issue, compared to *& on the end which, as you noted previously, is unusual, and is easy to forget. Consider the error messages if one forgets to add *&.
Yeah, I think I agree. In 0x, there's also not much reason to use the old forms of enable_if as well other than portability to old compilers, so not making new templates for the reasons I mentioned would probably be silly in the long run. Seconding the idea of just making new templates. -- -Matt Calabrese

On 04/12/2011 01:02 PM, Matt Calabrese wrote:
On Tue, Apr 12, 2011 at 12:56 PM, Stewart, Robert<Robert.Stewart@sig.com>wrote:
That's a minor issue, compared to *& on the end which, as you noted previously, is unusual, and is easy to forget. Consider the error messages if one forgets to add *&.
Yeah, I think I agree. In 0x, there's also not much reason to use the old forms of enable_if as well other than portability to old compilers, so not making new templates for the reasons I mentioned would probably be silly in the long run. Seconding the idea of just making new templates.
It seems that template aliases would further improve the syntax, but they are not yet supported by any compilers as far as I know. A macro could also lead to much shorter syntax.

On Tue, Apr 12, 2011 at 4:34 PM, Jeremy Maitin-Shepard <jeremy@jeremyms.com>wrote:
It seems that template aliases would further improve the syntax, but they are not yet supported by any compilers as far as I know.
Would SFINAE actually apply there or is that a level of indirection, causing a hard error? To be clear, I'm imagining something like this: template< bool V > struct enable_when_c_impl {}; template<> struct enable_when_c_impl< true > { typedef int type; }; template< bool V > using enable_when_c = typename enable_when_c_impl< V >::type; // SFINAE or error here when the condition is false? template< class T, enable_when_c< sizeof( T ) == 4 > = 0 > void foo( T ); -- -Matt Calabrese

On Wed, Apr 13, 2011 at 1:56 AM, Stewart, Robert <Robert.Stewart@sig.com> wrote:
You're right regarding references, of course, but a pointer to const should allow initialization from 0, right?
It's interesting no compiler I know of currently support it. C++0x draft 14.3.2 [temp.arg.nontype] paragraph 1, allows non-type template argument to be a constant expression that evaluates to a null pointer value or null member pointer value. Quick searching tells me this change was made in N1905(2005-10-19). -- Ryou Ezoe

I was experimenting with exactly the same technique about a year ago, but had some problems with overloading 2 or more variants of the same function. Think std:: advance. The problems may have been GCC specific and since resolved. What compiler are you using? On Apr 11, 2011 1:16 PM, "Matt Calabrese" <rivorus@gmail.com> wrote:
I'm not sure if there is much interest in this or if someone else discovered this as well, but I realized today that enable_if can be used in a new way in C++0x. Traditionally when working with enable_if with function templates you invoke it either in the return type or in an additional function parameter of the function. Each of these has advantages and disadvantages.
The parameter form has the downside of augmenting the parameter list. The most notable problems with this approach are that it can't be used with overloaded operators that require a fixed number of arguments, and it can't be used after a variadic argument list.
The return type use of enable_if is often preferred since it does not involve augmenting the parameter list, meaning that it can be used with most overloaded operators, but you still can't use it for conversion operations and you can't use it all with constructors as they have no explicit return type.
However, in C++0x, there is a new way to use enable_if by altering neither the function parameter list nor the specification of the return type. It can be used with operators, constructors, variadic function templates, and even overloaded conversion operations (the latter of which was previously considered impossible). The way to do it is with C++0x default function template parameters.
Rather than try to explain any further in English, the following code should demonstrate the approach fairly clearly (tested in GCC 4.5.2): http://codepaste.net/23yo8o
There is only one drawback that I can think of off of the top of my head -- you can't refer to the function parameters by name for the enable_if condition, whereas in C++0x if you use the return type form of enable_if along with the new trailing return type form of function declarations you can. I have never personally wanted to do this and I highly doubt that it's common so this is likely entirely a non-issue, plus you can always use std::declval anyway so you aren't actually losing any high-level functionality. Are there any thoughts on this or drawbacks other than what I mentioned? Should such use be added to the docs as supported behavior in 0x compilers?
-- -Matt Calabrese _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 11.04.2011, at 20:15, Matt Calabrese wrote:
However, in C++0x, there is a new way to use enable_if by altering neither the function parameter list nor the specification of the return type. It can be used with operators, constructors, variadic function templates, and even overloaded conversion operations (the latter of which was previously considered impossible). The way to do it is with C++0x default function template parameters.
That's really nice, but I think the syntax might be improved. How about adding a ::value to enable_if (and the other templates) to allow your example to look like this: template< class... T, bool = boost::enable_if_c< sizeof...( T ) == 10 >::value > test( T&&... ); template< class T, bool = boost::enable_if< boost::is_arithmetic< T > >::value > operator T() const; etc.? Get rid of typename, *&, boost::enabler and if you like, you can write 'bool Enabled = ...' instead of 'bool = ...' to be more verbose in your code. Of course, ::value is non-existent if the condition of enable_if is not met, it is not false. I made a quick test with gcc 4.6.0 and it seems to work fine. Plus it allows extending the existing enable_if without breaking anything (AFAICS). Regards, Daniel

On Wed, Apr 13, 2011 at 5:14 PM, Daniel Frey <d.frey@gmx.de> wrote:
On 11.04.2011, at 20:15, Matt Calabrese wrote:
However, in C++0x, there is a new way to use enable_if by altering neither the function parameter list nor the specification of the return type. It can be used with operators, constructors, variadic function templates, and even overloaded conversion operations (the latter of which was previously considered impossible). The way to do it is with C++0x default function template parameters.
That's really nice, but I think the syntax might be improved. How about adding a ::value to enable_if (and the other templates) to allow your example to look like this:
template< class... T, bool = boost::enable_if_c< sizeof...( T ) == 10 >::value > test( T&&... );
template< class T, bool = boost::enable_if< boost::is_arithmetic< T > >::value > operator T() const;
etc.? Get rid of typename, *&, boost::enabler and if you like, you can write 'bool Enabled = ...' instead of 'bool = ...' to be more verbose in your code. Of course, ::value is non-existent if the condition of enable_if is not met, it is not false. I made a quick test with gcc 4.6.0 and it seems to work fine. Plus it allows extending the existing enable_if without breaking anything (AFAICS).
It does not allow you to overload like this. template < typename T, bool = boost::enable_if_c< std::is_pointer<T>::value >::value > void f( T ) { } template < typename T, bool = boost::enable_if_c< std::is_arithmetic<T>::value >::value > void f( T ) { } I think ::type * = nullptr-or-0 is enough for this.(works on C++0x, don't work on C++03) Once compilers implemented true C++0x which allows null pointer constant as a non-type template argument. Until then, enabler is a workaround that works. But default template-argument for function template is a C++0x feature too. boost::enabler is not necessary for preventing mistakes. I think users rarely use explicit template argument specification. -- Ryou Ezoe

On Wed, Apr 13, 2011 at 4:14 AM, Daniel Frey <d.frey@gmx.de> wrote:
That's really nice, but I think the syntax might be improved. How about adding a ::value to enable_if (and the other templates) to allow your example to look like this:
Please reread the thread. I already explained why that doesn't work (see my responses to Gevorg). You need to use a non-type template argument that get's SFINAE'd otherwise you create multiple overloads that differ only in default arguments. -- -Matt Calabrese

Den 13-04-2011 10:14, Daniel Frey skrev:
On 11.04.2011, at 20:15, Matt Calabrese wrote:
That's really nice, but I think the syntax might be improved. How about adding a ::value to enable_if (and the other templates) to allow your example to look like this:
template< class... T, bool = boost::enable_if_c< sizeof...( T ) == 10>::value> test( T&&... );
template< class T, bool = boost::enable_if< boost::is_arithmetic< T> >::value> operator T() const;
etc.? Get rid of typename, *&, boost::enabler and if you like, you can write 'bool Enabled = ...' instead of 'bool = ...' to be more verbose in your code.
Hm. Why not template< class T, BOOST_ENABLE_WHEN( boost::is_xxx<T> ) > ? -Thorsten

On Wed, Apr 13, 2011 at 1:17 PM, Thorsten Ottosen < thorsten.ottosen@dezide.com> wrote:
template< class T, BOOST_ENABLE_WHEN( boost::is_xxx<T> ) >
This is the best so far, I think, and avoids the mistakes people keep making. Also, no need for calling it "enable when" anymore, you might as well just call it BOOST_ENABLE_IF. We also no longer need new templates. -- -Matt Calabrese

On Wed, Apr 13, 2011 at 10:17 AM, Thorsten Ottosen < thorsten.ottosen@dezide.com> wrote:
Den 13-04-2011 10:14, Daniel Frey skrev:
On 11.04.2011, at 20:15, Matt Calabrese wrote:
That's really nice, but I think the syntax might be improved. How
about adding a ::value to enable_if (and the other templates) to allow your example to look like this:
template< class... T, bool = boost::enable_if_c< sizeof...( T ) == 10>::value> test( T&&... );
template< class T, bool = boost::enable_if< boost::is_arithmetic< T> >::value> operator T() const;
etc.? Get rid of typename, *&, boost::enabler and if you like, you can write 'bool Enabled = ...' instead of 'bool = ...' to be more verbose in your code.
Hm. Why not
template< class T, BOOST_ENABLE_WHEN( boost::is_xxx<T> ) >
?
That would likely have issues with commas in the conditional, which I don't think "double parens" could fix. That is, it's a problem unless all C++0x compilers which support this use of SFINAE also support variadic templates... - Jeff

On Wed, Apr 13, 2011 at 1:35 PM, Jeffrey Lee Hellrung, Jr. < jeffrey.hellrung@gmail.com> wrote:
That would likely have issues with commas in the conditional, which I don't think "double parens" could fix. That is, it's a problem unless all C++0x compilers which support this use of SFINAE also support variadic templates...
I assume you mean variadic macros not variadic templates? Double parentheses would work fine when the compiler doesn't support variadic macros. Just define the macro as such, or similar: #define BOOST_ENABLE_IF( condition )\ typename ::boost::enable_if\ < typename ::boost::function_traits< void condition >::arg1_type\ , int >::type = 0 In fact it's possible to supply a simple variadic version when available and a regular macro similar to the one above when not, having the same macro name in either case without issue. You'd do this by making the variadic version check if the argument is parenthesized (which is possible with the preprocessor) and simply strip the parentheses if they are there. This allows backward compatibility by allowing people to specify either parenthesized or unparenthesized arguments. Anyway, all of this parentheses hubbub is probably unecessary since as far as I know all compilers that have any experimental C++0x support already also support variadic macros (probably in part because of C99). -- -Matt Calabrese

On Wed, Apr 13, 2011 at 11:02 AM, Matt Calabrese <rivorus@gmail.com> wrote:
On Wed, Apr 13, 2011 at 1:35 PM, Jeffrey Lee Hellrung, Jr. < jeffrey.hellrung@gmail.com> wrote:
That would likely have issues with commas in the conditional, which I don't think "double parens" could fix. That is, it's a problem unless all C++0x compilers which support this use of SFINAE also support variadic templates...
I assume you mean variadic macros not variadic templates?
Yes, my mistake!
Double parentheses would work fine when the compiler doesn't support variadic macros. Just define the macro as such, or similar:
#define BOOST_ENABLE_IF( condition )\ typename ::boost::enable_if\ < typename ::boost::function_traits< void condition >::arg1_type\ , int >::type = 0
Ah, clever, I hadn't seen or thought of that trick before. Well that makes my comment null and void. In fact it's possible to supply a simple variadic version when available and
a regular macro similar to the one above when not, having the same macro name in either case without issue. You'd do this by making the variadic version check if the argument is parenthesized (which is possible with the preprocessor) and simply strip the parentheses if they are there. This allows backward compatibility by allowing people to specify either parenthesized or unparenthesized arguments.
Right. Anyway, all of this parentheses hubbub is probably unecessary since as far
as I know all compilers that have any experimental C++0x support already also support variadic macros (probably in part because of C99).
Yeah, I wasn't sure about this. That covers any potential objections I had to the ENABLE_IF macro, and then some! Thanks Matt. - Jeff
participants (16)
-
Andrew Sutton
-
Beman Dawes
-
Daniel Frey
-
Gevorg Voskanyan
-
Jeffrey Lee Hellrung, Jr.
-
Jeremiah Willcock
-
Jeremy Maitin-Shepard
-
Krzysztof Czainski
-
Matt Calabrese
-
Noah Roberts
-
Ryou Ezoe
-
Steven Watanabe
-
Stewart, Robert
-
Stirling Westrup
-
Thorsten Ottosen
-
Vicente BOTET