Specializing Perfect Forwarding Templates?

Discussion in 'C++' started by Scott Meyers, Mar 16, 2011.

  1. Scott Meyers

    Scott Meyers Guest

    Function templates can be partially or fully specialized, but is it
    possible to specialize templates that perform perfect forwarding? My
    sense is that it's not, because the special type deduction rule that
    makes perfect forwarding work (the one that distinguishes lvalue and
    rvalue arguments for function templates with a declared parameter type
    of T&& -- 14.8.2.1/3 in the most recent draft C++0x) seems to apply only
    to general templates. But maybe I'm overlooking something.

    If I give the program below to VC10 and gcc 4.5, they behave as the
    comments indicate. My attempt to partially specialize a perfect
    forwarding template for pointer types fails. The code compiles and
    runs, but the partial specialization is invoked only for rvalue pointer
    types, never for lvalue pointer types.

    I have two questions:
    1. Am I correct that perfect forwarding templates cannot be specialized?
    2. Does it ever make sense to want to?

    Thanks,

    Scott



    #include <iostream>
    #include <utility>

    void f(std::string*&)
    {
    std::cout << "f(lref)\n";
    }

    void f(const std::string*&)
    {
    std::cout << "f(const lref)\n";
    }

    void f(std::string*&&)
    {
    std::cout << "f(rref)\n";
    }

    template<typename T>
    void fwd(T&& param)
    {
    std::cout << "General forwarding template => ";
    f(std::forward<T>(param));
    }

    template<typename T>
    void fwd(T*&& param)
    {
    std::cout << "T*&& forwarding template => ";
    f(std::forward<T*>(param));
    }

    int main()
    {
    std::string* ps;
    const std::string *pcs;

    fwd(ps); // calls general template
    fwd(pcs); // calls general template
    fwd((std::string*&&)ps); // calls specialized template
    }
     
    Scott Meyers, Mar 16, 2011
    #1
    1. Advertising

  2. * Scott Meyers, on 16.03.2011 06:22:
    > Function templates can be partially or fully specialized,


    Sorry, but at which version have partial specialization of function templates
    been introduced, and can you give reference?

    AFAIK what looks like a partial specialization is still just overloading.


    > but is it possible to
    > specialize templates that perform perfect forwarding? My sense is that it's not,
    > because the special type deduction rule that makes perfect forwarding work (the
    > one that distinguishes lvalue and rvalue arguments for function templates with a
    > declared parameter type of T&& -- 14.8.2.1/3 in the most recent draft C++0x)
    > seems to apply only to general templates. But maybe I'm overlooking something.
    >
    > If I give the program below to VC10 and gcc 4.5, they behave as the comments
    > indicate. My attempt to partially specialize a perfect forwarding template for
    > pointer types fails. The code compiles and runs, but the partial specialization
    > is invoked only for rvalue pointer types, never for lvalue pointer types.
    >
    > I have two questions:
    > 1. Am I correct that perfect forwarding templates cannot be specialized?
    > 2. Does it ever make sense to want to?
    >
    > Thanks,
    >
    > Scott
    >
    >
    >
    > #include <iostream>
    > #include <utility>
    >
    > void f(std::string*&)
    > {
    > std::cout << "f(lref)\n";
    > }
    >
    > void f(const std::string*&)
    > {
    > std::cout << "f(const lref)\n";
    > }
    >
    > void f(std::string*&&)
    > {
    > std::cout << "f(rref)\n";
    > }
    >
    > template<typename T>
    > void fwd(T&& param)
    > {
    > std::cout << "General forwarding template => ";
    > f(std::forward<T>(param));
    > }
    >
    > template<typename T>
    > void fwd(T*&& param)
    > {
    > std::cout << "T*&& forwarding template => ";
    > f(std::forward<T*>(param));
    > }
    >
    > int main()
    > {
    > std::string* ps;
    > const std::string *pcs;
    >
    > fwd(ps); // calls general template
    > fwd(pcs); // calls general template
    > fwd((std::string*&&)ps); // calls specialized template
    > }


    Well it's late in the day for me, but fiddling a little with your code produced
    an apparent difference between the general template and the pointer arg template:


    <code>
    #include <iostream>
    #include <utility>

    void f(std::string*&)
    {
    std::cout << "f(lref)\n";
    }

    void f(const std::string*&)
    {
    std::cout << "f(const lref)\n";
    }

    void f(std::string*&&)
    {
    std::cout << "f(rref)\n";
    }

    template<typename T>
    void fwd(T&& param)
    {
    std::cout << "General forwarding template => ";
    f(std::forward<T>(param));
    }

    template<typename T>
    void ptrfwd(T*&& param)
    {
    std::cout << "T*&& forwarding template => ";
    f( std::forward<T*>(param));
    }

    template<typename T>
    void fwd(T*&& param)
    { ptrfwd( std::forward<T*>(param) ); }

    template<typename T>
    void fwd(T*& param)
    { ptrfwd( param ); }

    int main()
    {
    std::string* ps = 0;
    const std::string *pcs = 0;

    fwd(ps); // calls general template
    fwd(pcs); // calls general template
    fwd((std::string*&&)ps); // calls specialized template
    }
    </code>


    <compilation>
    C:\test> msvc x.cpp
    x.cpp
    x.cpp(39) : error C2664: 'ptrfwd' : cannot convert parameter 1 from 'std::string
    *' to 'std::string *&&'
    You cannot bind an lvalue to an rvalue reference
    x.cpp(46) : see reference to function template instantiation 'void
    fwd<std::string>(T *&)' being compiled
    with
    [
    T=std::string
    ]
    x.cpp(39) : error C2664: 'ptrfwd' : cannot convert parameter 1 from 'const
    std::string *' to 'const std::string *&&'
    You cannot bind an lvalue to an rvalue reference
    x.cpp(47) : see reference to function template instantiation 'void
    fwd<const std::string>(T *&)' being compiled
    with
    [
    T=const std::string
    ]

    C:\test> _
    </compilation>


    Why this result, cannot bind lvalue to rvalue-ref, when 'ptrwfd' is a general
    template?


    Cheers & hth.,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach /Usenet, Mar 16, 2011
    #2
    1. Advertising

  3. * Scott Meyers, on 16.03.2011 06:22:
    >
    > I have two questions:
    > 1. Am I correct that perfect forwarding templates cannot be specialized?


    Code below seems to work OK:


    <code>
    #include <iostream>
    #include <utility>

    void f(std::string*&)
    {
    std::cout << "f(lref)\n";
    }

    void f(const std::string*&)
    {
    std::cout << "f(const lref)\n";
    }

    void f(std::string*&&)
    {
    std::cout << "f(rref)\n";
    }

    template<typename T>
    void fwd(T&& param)
    {
    std::cout << "General forwarding template => ";
    f(std::forward<T>(param));
    }

    template<typename T>
    void ptrfwd(T&& param)
    {
    //STATIC_ASSERT( T is pointer type )
    std::cout << "T*&& forwarding template => ";
    f( std::forward<T>(param));
    }

    template<typename T>
    void fwd(T*&& param)
    { ptrfwd( std::forward<T*>(param) ); }

    template<typename T>
    void fwd(T*& param)
    { ptrfwd( param ); }

    int main()
    {
    std::string* ps = 0;
    const std::string *pcs = 0;

    fwd(ps); // calls specialized template
    fwd(pcs); // calls specialized template
    fwd((std::string*&&)ps); // calls specialized template
    }
    </code>


    Cheers & hth.,

    - Alf (hey, why don't you mention me somewhere? I wanna be fammous! lol)

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach /Usenet, Mar 16, 2011
    #3
  4. Scott Meyers

    SG Guest

    On 16 Mrz., 06:22, Scott Meyers wrote:
    > Function templates can be partially or fully specialized,


    Can they be? partially specialized? If so, this would be a new C++0x
    feature. I take your word for it.

    > but is it
    > possible to specialize templates that perform perfect forwarding?


    The code you provided does not contain a partial specialization of a
    function template. You *overloaded* the function template fwd with
    another "more specialized" one. That's different.

    > void f(std::string*&)
    > {
    >    std::cout << "f(lref)\n";
    > }
    >
    > void f(const std::string*&)
    > {
    >    std::cout << "f(const lref)\n";
    > }
    >
    > void f(std::string*&&)
    > {
    >    std::cout << "f(rref)\n";
    > }
    >
    > template<typename T>
    > void fwd(T&& param)
    > {
    >    std::cout << "General forwarding template => ";
    >    f(std::forward<T>(param));
    > }
    >
    > template<typename T>
    > void fwd(T*&& param)
    > {
    >    std::cout << "T*&& forwarding template => ";
    >    f(std::forward<T*>(param));
    > }


    From your use of std::forward I gather that you expect this template
    to catch pointer lvalues and rvalues. But the deduction rule that
    makes perfect forwarding possible is restricted to a function
    parameter pattern "T&&" where T is a template parameter. Perfect
    forwarding not only relies on the deduction rules but also on
    reference collapsing. So, to make T&& an lvalue reference we just set
    T to be an lvalue reference (or let the compiler deduce it to be an
    lvalue reference). Reference collapsing makes T&& with T=U& into
    T&&=U&. But T*&& can *never* be an lvalue reference regardless of what
    T is. T*&& is *always* an rvalue reference.

    SG
     
    SG, Mar 16, 2011
    #4
  5. Scott Meyers

    Scott Meyers Guest

    On 3/16/2011 12:20 AM, Alf P. Steinbach /Usenet wrote:
    > * Scott Meyers, on 16.03.2011 06:22:
    >> Function templates can be partially or fully specialized,

    >
    > Sorry, but at which version have partial specialization of function
    > templates been introduced, and can you give reference?
    >
    > AFAIK what looks like a partial specialization is still just overloading.


    You're right, my bad. Please forgive my terminological sin.

    > Code below seems to work OK:


    [...]

    > template<typename T>
    > void fwd(T*&& param)
    > { ptrfwd( std::forward<T*>(param) ); }
    >
    > template<typename T>
    > void fwd(T*& param)
    > { ptrfwd( param ); }


    But notice how you have to overload to support both lvalues and rvalues.
    This doesn't scale with multiple parameters, which is the motivation
    for perfect forwarding: to be able to write one template that handles
    both. If I could "partially specialize" a forwarding template for
    pointer types, I'd be able to write a single template to handle all
    pointer types, both lvalues and rvalues.

    Scott
     
    Scott Meyers, Mar 16, 2011
    #5
  6. Scott Meyers

    Scott Meyers Guest

    On 3/16/2011 12:31 AM, SG wrote:
    > Can they be? partially specialized? If so, this would be a new C++0x
    > feature. I take your word for it.


    No, as I pointed out in a response to a different post, I made the
    common error of saying "specialization" when I meant overloading. I
    hang my head in shame.

    > From your use of std::forward I gather that you expect this template
    > to catch pointer lvalues and rvalues. But the deduction rule that
    > makes perfect forwarding possible is restricted to a function
    > parameter pattern "T&&" where T is a template parameter.


    Which is what I said I thought was the case. I was just wondering if I
    had overlooked something somewhere. Even in draft form, it would not be
    breaking new ground for the C++ standard to grant permission to do
    something in one place that appears to not be permitted based on other
    parts of the standard.

    Scott
     
    Scott Meyers, Mar 16, 2011
    #6
  7. Scott Meyers

    SG Guest

    On 16 Mrz., 09:05, Scott Meyers wrote:
    > SG wrote:
    > > From your use of std::forward I gather that you expect this template
    > > to catch pointer lvalues and rvalues. But the deduction rule that
    > > makes perfect forwarding possible is restricted to a function
    > > parameter pattern "T&&" where T is a template parameter.

    >
    > Which is what I said I thought was the case.  I was just wondering if I
    > had overlooked something somewhere.  Even in draft form, it would not be
    > breaking new ground for the C++ standard to grant permission to do
    > something in one place that appears to not be permitted based on other
    > parts of the standard.


    You make it sound like if it was an artificial restriction that could
    be easily overcome. But this is not the case. To get what you want we
    would need some kind of constrained template and new overload
    resolution rules based on these constraints. Example:

    template<class T>
    requires T=U* or T=U*& for some type U
    void fwd(T&&);

    SG
     
    SG, Mar 16, 2011
    #7
  8. Scott Meyers

    SG Guest

    On 16 Mrz., 09:33, SG wrote:
    > [...] To get what you want we
    > would need some kind of constrained template and new overload
    > resolution rules based on these constraints. Example:
    >
    >   template<class T>
    >   requires T=U* or T=U*& for some type U
    >   void fwd(T&&);


    Or an alternative way to do perfect forwarding. You *did* point out
    with your example that deduction w.r.t. "special, more restrictive
    patters" a la T* is not orthogonal to the feature that allows us to
    detect lvalues and rvalues. So, for a proper "orthogonal" approach we
    could introduce a new kind of template parameter:

    template<class T, qualifier Q>
    void fwd(T* Q x);

    where Q can be one of the 12=2*2*3 combinations you get by pairing
    const/non-const, volatile/non-volatile and [no reference]/&/&&. The
    deduction rule for Q would pick an lvalue reference for lvalues and an
    rvalue reference for rvalues.

    This way, we get rid of the issue you pointed out (w.r.t.
    orthogonality), we can get rid of the funny/special deduction rule for
    T&& (which is already known to cause trouble (*)) and also get a nice
    way of expressing member function types

    template<class R, class C, qualifier Q, class... P>
    void (R (C::*memfunptr)(P...) Q);

    without the need to overload std::bind for 12 different combinations
    of qualifiers.

    On the other hand, getting rid of the funny/special deduction rule for
    the "T&&" pattern would force us to use two template parameters to do
    perfect forwarding for just one function argument:

    template<class...P, qualifiers...Q>
    void outer(P Q... params)
    {
    inner(std::forward<P Q>(params)...);
    }

    I'm not sure about other implications, but it seems to be worth
    thinking about it.

    Cheers!
    SG
     
    SG, Mar 16, 2011
    #8
  9. Scott Meyers

    itaj sherman Guest

    On Mar 16, 7:22 am, Scott Meyers <> wrote:
    > Function templates can be partially or fully specialized, but is it
    > possible to specialize templates that perform perfect forwarding? My
    > sense is that it's not, because the special type deduction rule that
    > makes perfect forwarding work (the one that distinguishes lvalue and
    > rvalue arguments for function templates with a declared parameter type
    > of T&& -- 14.8.2.1/3 in the most recent draft C++0x) seems to apply only
    > to general templates. But maybe I'm overlooking something.
    >


    What is supposed to happen if you wrap it into template class
    specializations?

    template< typename T >
    class fwd_internal
    {
    public:
    template<typename U>
    static void call(U&& param)
    {
    std::cout << "General forwarding template => ";
    f(std::forward<U>(param));
    }
    }

    template< typename T* >
    class fwd_internal
    {
    public:
    template<typename U>
    static void call(U&& param)
    {
    std::cout << "T*&& forwarding template => ";
    f(std::forward<U>(param));
    }
    }

    template<typename T>
    void fwd(T&& param)
    {
    return fwd_internal<T>::call(std::forward<T>(param));
    }

    itaj
     
    itaj sherman, Mar 16, 2011
    #9
  10. Scott Meyers

    itaj sherman Guest

    On Mar 16, 1:10 pm, itaj sherman <> wrote:

    oops specialization syntax:

    >
    > template< typename T* >
    > class fwd_internal


    template< typename T >
    class fwd_internal< T* >

    itaj
     
    itaj sherman, Mar 16, 2011
    #10
  11. Scott Meyers

    crea Guest

    >Scott Meyers wrote:

    Are you the Scott Meyers who wrotes foreword to book "Modern C++ Design" ?
     
    crea, Mar 16, 2011
    #11
  12. Scott Meyers

    SG Guest

    On 16 Mrz., 12:12, itaj sherman wrote:
    > On Mar 16, 1:10 pm, itaj sherman wrote:
    >
    > oops specialization syntax:
    >
    > > template< typename T* >
    > > class fwd_internal

    >
    > template< typename T >
    > class fwd_internal< T* >


    In addition, you have to replace

    fwd_internal<T>::call(etc);

    with

    typedef typename std::decay<T>::type Td;
    fwd_internal<Td>::call(etc);

    to get rid of cv qualifiers and the case when T is deduced to to be an
    lvalue reference due to the "funny/special" deduction rule that allows
    perfect forwarding.

    Cheers!
    SG
     
    SG, Mar 16, 2011
    #12
  13. Scott Meyers

    Balog Pal Guest

    Balog Pal, Mar 16, 2011
    #13
  14. Scott Meyers

    Noah Roberts Guest

    On 3/15/2011 10:22 PM, Scott Meyers wrote:

    > template<typename T>
    > void fwd(T*&& param)
    > {
    > std::cout << "T*&& forwarding template => ";
    > f(std::forward<T*>(param));
    > }
    >


    Couple issues here. T can never cause reference "decay". If T is an
    lvalue reference then you have the strange parameter type "T&*&&". If T
    is an rvalue reference then you have the strange parameter type
    "T&&*&&". To implement a perfect forwarding function you need to be
    relying on the fact that & && is & and && && is && so that when T is an
    lvalue reference, the parameter to the function is, and visa-versa.

    Second issue is that std::forward works similarly. It's simply a
    template function that takes a T&& and returns T.

    Since the parameter for your function is always going to be an rvalue
    reference you can expect that lvalue references can't be passed into it
    without calling std::move.

    You can do what you're trying to do with a dispatching pattern:

    #include <iostream>
    #include <type_traits>

    template < bool Match >
    struct function_impl
    {
    template < typename T >
    static void apply(T&& t)
    {
    std::cout << "Generic version called.\n";
    }
    };

    template < >
    struct function_impl<true>
    {
    template < typename T >
    static void apply(T&& t)
    {
    std::cout << "Specific version called.\n";
    }
    };

    template < typename T >
    void f(T&& t)
    {
    function_impl< std::is_pointer< typename
    std::remove_reference<T>::type >::value >::apply(std::forward<T>(t));
    }

    int * get_ptr() { return nullptr; }
    int get_value() { return 0; }

    int main()
    {
    int val = get_value();
    int * ptr = get_ptr();

    f(val);
    f(ptr);
    f(get_value());
    f(get_ptr());
    }

    Specific needs may of course mean a more complicated construct.

    --
    http://crazycpp.wordpress.com
     
    Noah Roberts, Mar 16, 2011
    #14
  15. Scott Meyers

    Scott Meyers Guest

    On 3/16/2011 9:47 AM, Noah Roberts wrote:
    > You can do what you're trying to do with a dispatching pattern:


    Simple testing suggests I can achieve the same end with less work and
    using an arguably clearer approach via enable_if. Overloading my
    forwarding template as follows works for me with VC10 and gcc 4.5 (on
    simple tests):

    template<typename T>
    typename std::enable_if<
    !std::is_pointer<
    typename std::remove_reference<T>::type
    >::value
    >::type

    fwd(T&& param)
    {
    std::cout << "General forwarding template => ";
    f(std::forward<T>(param));
    }

    template<typename T>
    typename std::enable_if<
    std::is_pointer<
    typename std::remove_reference<T>::type
    >::value
    >::type

    fwd(T&& param)
    {
    std::cout << "Pointer forwarding template => ";
    f(std::forward<T>(param));
    }

    Am I overlooking a drawback to this technique?

    While playing around with this, I was surprised to find that there is no
    disable_if in C++0x. Yes, there's no need for it (as shown above), but
    it has an established usage history (e.g., in Boost). Does anybody
    happen to know why it's not in C++0x?

    Thanks,

    Scott

    --
    * C++ and Beyond: Meyers, Sutter, & Alexandrescu, Aug. 7-10 in Banff
    (http://cppandbeyond.com/)
     
    Scott Meyers, Mar 16, 2011
    #15
  16. Scott Meyers

    Noah Roberts Guest

    On 3/16/2011 10:20 AM, Scott Meyers wrote:
    > On 3/16/2011 9:47 AM, Noah Roberts wrote:
    >> You can do what you're trying to do with a dispatching pattern:

    >
    > Simple testing suggests I can achieve the same end with less work and
    > using an arguably clearer approach via enable_if.


    Entirely possible as you show. Arguably cleaner but I tend to disagree.
    I've found that although enable_if works reasonably well when you're
    trying to match specific concepts and/or types, when you begin having to
    exclude these concepts in the other overloads/specializations to resolve
    ambiguity the scaling factor explodes and it tends, in my opinion, to be
    less legible than dispatching versions.

    If, for example, you needed to overload both versions for some specific
    concept, a combination of dispatching at the is_pointer level and either
    enable_if or a different dispatch for the function call would probably
    end up in slightly more legible code. It would also tend to create more
    reuse because the is_pointer bit is already resolved by the general layer.

    > Am I overlooking a drawback to this technique?


    Scalability would be my primary technical concern. Preference would
    guide me to prefer the dispatch version otherwise, though I'm sure I
    could be convinced otherwise by a good reason to prefer the enable_if
    version.

    >
    > While playing around with this, I was surprised to find that there is no
    > disable_if in C++0x. Yes, there's no need for it (as shown above), but
    > it has an established usage history (e.g., in Boost). Does anybody
    > happen to know why it's not in C++0x?


    I wouldn't really know. Perhaps it was just one less thing to argue
    about :p

    --
    http://crazycpp.wordpress.com
     
    Noah Roberts, Mar 16, 2011
    #16
  17. Scott Meyers

    Marc Guest

    Scott Meyers wrote:

    > Simple testing suggests I can achieve the same end with less work and
    > using an arguably clearer approach via enable_if. Overloading my
    > forwarding template as follows works for me with VC10 and gcc 4.5 (on
    > simple tests):
    >
    > template<typename T>
    > typename std::enable_if<
    > !std::is_pointer<
    > typename std::remove_reference<T>::type
    > >::value
    > >::type

    > fwd(T&& param)
    > {
    > std::cout << "General forwarding template => ";
    > f(std::forward<T>(param));
    > }
    >
    > template<typename T>
    > typename std::enable_if<
    > std::is_pointer<
    > typename std::remove_reference<T>::type
    > >::value
    > >::type

    > fwd(T&& param)
    > {
    > std::cout << "Pointer forwarding template => ";
    > f(std::forward<T>(param));
    > }
    >
    > Am I overlooking a drawback to this technique?


    That's the natural solution, but it doesn't scale so nicely if you
    want to have several specializations. Besides, you need to know all
    specializations in advance. Hence the solutions using a traits class
    or a dispatcher class or...

    > While playing around with this, I was surprised to find that there is no
    > disable_if in C++0x. Yes, there's no need for it (as shown above), but
    > it has an established usage history (e.g., in Boost).


    I didn't even know it was in boost. It just seems so natural to negate
    the argument...
     
    Marc, Mar 16, 2011
    #17
  18. Scott Meyers

    Scott Meyers Guest

    On 3/16/2011 10:44 AM, Marc wrote:
    > I didn't even know it was in boost. It just seems so natural to negate
    > the argument...


    As far as I know, it's been around pretty much since the beginning. The
    first time I read about enable_if was in the 2003 C/C++ Users Journal
    article (available at http://drdobbs.com/cpp/184401659 ), and disable_if
    was introduced in the same sentence as enable_if.

    Scott

    --
    * C++ and Beyond: Meyers, Sutter, & Alexandrescu, Aug 7-10 in Banff
    (http://cppandbeyond.com/)
     
    Scott Meyers, Mar 16, 2011
    #18
  19. Scott Meyers

    SG Guest

    On 16 Mrz., 18:44, Marc wrote:
    > Scott Meyers  wrote:
    > > [...]

    > [...] but it doesn't scale so nicely if you
    > want to have several specializations. Besides, you need to know all
    > specializations in advance.


    Exactly. This is because there is no partial ordering for multiple
    matches since these "constraints" are not considered during overload
    resolution.

    Concepts indented to fix that by concept-based overloading where the
    partial ordering is established via concept inheritance. One work
    around for the lack of concept-based overloading is tag dispatching.
    But this also requires one additional layer of indirection and is not
    any better than the approaches that have been shown here already.

    SG
     
    SG, Mar 16, 2011
    #19
  20. Scott Meyers

    Noah Roberts Guest

    On 3/16/2011 10:20 AM, Scott Meyers wrote:

    > While playing around with this, I was surprised to find that there is no
    > disable_if in C++0x. Yes, there's no need for it (as shown above), but
    > it has an established usage history (e.g., in Boost). Does anybody
    > happen to know why it's not in C++0x?


    Actually, there's a significant difference between std::enable_if and
    boost::enable_if that may be the main reason why disable_if is in boost
    and not std.

    std::enable_if< !is_pointer<T>::value ... >

    That's ok.

    boost::enable_if< !is_pointer<T>::value ... >

    Not ok. You either need to use enable_if_c or something like so:

    boost::enable_if< boost::mpl::not_< is_pointer<T> > ... >

    Since "metafunction" didn't make it into the standard that I know of it
    would be hard to specify an enable_if that used one. Since its easy to
    negate a value, compared to a bool metafunction, it could be that the
    committee simply didn't see it as vital while it's certainly a benefit
    in boost. Once the decision was made to implement in terms of value
    rather than metafunction it probably just fell out.

    --
    http://crazycpp.wordpress.com
     
    Noah Roberts, Mar 16, 2011
    #20
    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. Scott Meyers
    Replies:
    6
    Views:
    971
    Scott Meyers
    Dec 5, 2010
  2. Andrew Tomazos
    Replies:
    1
    Views:
    1,004
    Andrew Tomazos
    Dec 23, 2011
  3. Alexis Nikichine

    Perfect function forwarding

    Alexis Nikichine, Dec 27, 2005, in forum: Javascript
    Replies:
    6
    Views:
    160
    Alexis Nikichine
    Dec 28, 2005
  4. dervih
    Replies:
    3
    Views:
    509
    dervih
    Jul 13, 2012
  5. Replies:
    3
    Views:
    342
Loading...

Share This Page