auto for function return type is kind of useless, is it?

Discussion in 'C++' started by Peter, Jan 17, 2012.

  1. Peter

    Peter Guest

    Posting this again, since google-groups may have swallowed it
    earlier...

    What is the use of the auto keyword for function return types,
    if I anway have to declare the type by hand after the function header?

    In this case I've could also have written the return type up front
    using the template types of the variables instead of variable names.

    Currently i'm writing all the code to be included in the function
    using macros,
    with the macro names matching the variable names.
    I do this since the code is needed twice
    -- once for the return type determination and once for the actual
    function body
    (this is some simple example demonstrating my approach.
    Imagine much bigger functions):

    Can somebody come up with a simpler approach?


    template<typename T0, typename T1>
    auto getSomething(const T0 &_r0, const T1&_r1)
    #define _a (_r0 + _r1)
    #define _b (_a*_a)
    #define _c (_b*_a)
    -> decltype(_c)
    {
    const auto a(_a);
    #undef _a
    #define _a a
    const auto b(_b);
    #undef _b
    #define _b b
    const auto c(_c);
    #undef _c
    #undef _b
    #undef _a
    return c;
    }
     
    Peter, Jan 17, 2012
    #1
    1. Advertising

  2. Peter

    Peter Guest

    Peter, Jan 18, 2012
    #2
    1. Advertising

  3. Peter <> wrote:
    > Can somebody come up with a simpler approach?
    >
    > template<typename T0, typename T1>
    > auto getSomething(const T0 &_r0, const T1&_r1)
    > #define _a (_r0 + _r1)
    > #define _b (_a*_a)
    > #define _c (_b*_a)
    > -> decltype(_c)
    > {
    > const auto a(_a);
    > #undef _a
    > #define _a a
    > const auto b(_b);
    > #undef _b
    > #define _b b
    > const auto c(_c);
    > #undef _c
    > #undef _b
    > #undef _a
    > return c;
    > }


    Are you entering an obfuscated C++ code contest or something? I have
    really hard time deciphering that.

    Anyways, what I think you want is this:

    template<typename T0, typename T1>
    auto getSomething(const T0& r0, const T1& r1)
    -> std::common_type<T0, T1>::type
    {
    const auto a = r0 + r1;
    const auto b = a * a;
    return b * a;
    }
     
    Juha Nieminen, Jan 18, 2012
    #3
  4. Peter

    SG Guest

    On Jan 17, 10:53 pm, Peter wrote:
    >
    > What is the use of the auto keyword for function return types,
    > if I anway have to declare the type by hand after the function header?


    One advantage is "scope". If you declare the return type at the end
    the compiler already knows the parameters including whether the
    function is a member function of not.

    One of the first examples to demonstrate the benifit was

    template<class T, class U>
    decltype(a+b) // FAILS, a and b are not yet known
    add(T a, U b);

    template<class T, class U>
    decltype(declval<T>()+declval<U>()) // works, but is tedious
    add (T a, U b);

    template<class T, class U>
    auto add(T a, U b)
    -> decltype(a+b); // fine, compiler knows what a and b are

    But it also works with member typedefs, for example:

    class myuserdefinedtype
    {
    public:
    typedef int something;
    auto bar() -> something;
    };

    auto myuserdefinedtype::bar() -> something
    {
    ...
    }

    instead of

    myuserdefinedtype::something myuserdefinedtype::bar()
    {
    ...
    }

    Unfortunately, the compiler allows omitting the return type entirely
    only for lambdas with a single return statement. I whish I could do
    the same for named functions. But it is possible to reduce redundancy
    using a macro:

    #define AUTO_RETURN(...) \
    -> typename std::decay<decltype(__VA_ARGS__)>::type \
    { return __VA_ARGS__; }

    template<class T, class U, class V>
    auto baz( T a, U b, V c )
    AUTO_RETURN( a*(b+c) )

    For more complicated functions (more than just a single return
    statement) I think it's okay to let the user specify the return type
    manually.
     
    SG, Jan 18, 2012
    #4
  5. Peter

    SG Guest

    On Jan 18, 8:40 am, Juha Nieminen wrote:
    >
    > template<typename T0, typename T1>
    > auto getSomething(const T0& r0, const T1& r1)
    > -> std::common_type<T0, T1>::type


    Hmm... It would be nice to be able to omit the typename keyword in
    this context (like you did). After all, what follows the arrow can
    only be a type. But right now, I'm not sure about whether this is
    allowed or you actually still have to insert "typename" before
    std::common_type<T0, T1>::type.

    Anyone knows for sure? I can imagine the Microsoft compiler being lax
    about it. So, a report like "MSVC compiles it" isn't good enough for
    me. ;-)

    Cheers!
    SG
     
    SG, Jan 18, 2012
    #5
  6. Peter

    Peter Guest

    On Jan 17, 11:40 pm, Juha Nieminen <> wrote:
    >   Anyways, what I think you want is this:
    >
    > template<typename T0, typename T1>
    > auto getSomething(const T0& r0, const T1& r1)
    > -> std::common_type<T0, T1>::type
    > {
    >     const auto a = r0 + r1;
    >     const auto b = a * a;
    >     return b * a;



    I don't see the code where you tell the compiler that the return type
    is decltype((_r0+_r1)*(_r0+_r1))*(_r0+_r1)).
     
    Peter, Jan 18, 2012
    #6
  7. Peter

    Peter Guest

    On Jan 18, 1:22 am, SG <> wrote:
    > On Jan 17, 10:53 pm, Peter wrote:
    >
    >
    >
    > > What is the use of the auto keyword for function return types,
    > > if I anway have to declare the type by hand after the function header?

    >
    > One advantage is "scope".  If you declare the return type at the end
    > the compiler already knows the parameters including whether the
    > function is a member function of not.
    >
    > One of the first examples to demonstrate the benifit was
    >
    >   template<class T, class U>
    >   decltype(a+b)   // FAILS, a and b are not yet known
    >   add(T a, U b);



    decltype(T()+U()) add(T a, U b)

    so the auto keyword does not help at all.
     
    Peter, Jan 18, 2012
    #7
  8. Peter

    SG Guest

    On Jan 18, 5:09 pm, Peter wrote:

    > I don't see the code where you tell the compiler that the return
    > type is decltype((_r0+_r1)*(_r0+_r1))*(_r0+_r1)).


    You don't have to use exactly the same expression for the return
    type. I expect that in many cases one can greatly simplify the
    decltype expression because it's only used for the type, not the
    value.

    > decltype(T()+U()) add(T a, U b)


    This only works in case T and and U are default-constructible. That's
    why I used std::declval<T>() and std::declval<U>() in my example.
    Surely 'a' and 'b' is much shorter than 'std::declval<T>()' and
    'std::declval<U>()'.

    > so the auto keyword does not help at all.


    That depends on what kind of problem you look at while considering
    auto. As I said, it's mainly about scope and also about readability.

    Cheers!
    SG
     
    SG, Jan 18, 2012
    #8
  9. Peter

    Peter Guest

    On Jan 18, 9:07 am, SG <> wrote:
    > On Jan 18, 5:09 pm, Peter wrote:
    >
    > > I don't see the code where you tell the compiler that the return
    > > type is decltype((_r0+_r1)*(_r0+_r1))*(_r0+_r1)).

    >
    > You don't have to use exactly the same expression for the return
    > type.



    I don't?
    In my case
    decltype(_r0+_r1)
    maybe different than
    decltype((_r0+_r1)*(_r0+_r1))
    which in turn may be different than
    decltype(std::sin(_r0+_r1))
    So please tell me how I can avoid having to write the code twice?
     
    Peter, Jan 18, 2012
    #9
  10. Peter

    SG Guest

    On 18 Jan., 18:46, Peter <> wrote:
    > On Jan 18, 9:07 am, SG <> wrote:
    >
    > > On Jan 18, 5:09 pm, Peter wrote:

    >
    > > > I don't see the code where you tell the compiler that the return
    > > > type is decltype((_r0+_r1)*(_r0+_r1))*(_r0+_r1)).

    >
    > > You don't have to use exactly the same expression for the return
    > > type.

    >
    > I don't?


    In general, no -- depends on the case and how "generic" you want to
    be. You snipped half of my comment which was intended to further
    qualify this statement of mine.

    For example, I would probably write something like this

    template<class T, class U>
    auto dot_product(vector<T> const& a, vector<U> const& b)
    -> decltype(a[0]*b[0]);

    expecting that

    decltype(a[0]*b[0]+a[1]*b[1]+...+a[n-1]*b[n-1])

    can be shortened to

    decltype(a[0]*b[0])

    In my opinion, this is a perfectly reasonable thing to do.

    Cheers!
    SG
     
    SG, Jan 18, 2012
    #10
  11. Peter <> wrote:
    > On Jan 17, 11:40 pm, Juha Nieminen <> wrote:
    >>   Anyways, what I think you want is this:
    >>
    >> template<typename T0, typename T1>
    >> auto getSomething(const T0& r0, const T1& r1)
    >> -> std::common_type<T0, T1>::type
    >> {
    >>     const auto a = r0 + r1;
    >>     const auto b = a * a;
    >>     return b * a;

    >
    >
    > I don't see the code where you tell the compiler that the return type
    > is decltype((_r0+_r1)*(_r0+_r1))*(_r0+_r1)).


    std::common_type::type is the resulting type of any arithmetic
    operations performed on the parameter types.
     
    Juha Nieminen, Jan 18, 2012
    #11
  12. Peter

    Peter Guest

    On Jan 17, 1:53 pm, Peter <> wrote:



    Guys -- this is ridiculous.

    Thanks for telling me, that the problem I'm facing does not exist!

    I was posting here to publish the unnecessary restrictions in the new C
    ++ standard
    and I may have hoped, that somebody may come up with a better method.

    I was of the opinion, that my original post contained enough
    information for all of this.
     
    Peter, Jan 18, 2012
    #12
  13. Peter

    Peter Guest

    On Jan 18, 10:52 am, Peter <> wrote:
    > On Jan 17, 1:53 pm, Peter <> wrote:
    >
    > Guys -- this is ridiculous.
    >
    > Thanks for telling me, that the problem I'm facing does not exist!
    >
    > I was posting here to publish the unnecessary restrictions in the new C
    > ++ standard
    > and I may have hoped, that somebody may come up with a better method.


    I mean to say:


    that somebody may come up with a better method than using macros the
    way I did...


    >
    > I was of the opinion, that my original post contained enough
    > information for all of this.
     
    Peter, Jan 18, 2012
    #13
  14. Peter <> wrote:
    > Guys -- this is ridiculous.
    >
    > Thanks for telling me, that the problem I'm facing does not exist!
    >
    > I was posting here to publish the unnecessary restrictions in the new C
    > ++ standard
    > and I may have hoped, that somebody may come up with a better method.
    >
    > I was of the opinion, that my original post contained enough
    > information for all of this.


    What exactly is the problem with std::common_type?

    It works with all basic types (for which arithmetic operators can be
    applied to) and any other type if the types are the same (for example it
    works with std::string just fine).

    It might not work with different classes that can be inter-mixed with
    the arithmetic operators. Haven't tested. OTOH, it's allowed for common_type
    to be specialized.
     
    Juha Nieminen, Jan 19, 2012
    #14
  15. Peter

    SG Guest

    > On Jan 17, 1:53 pm, Peter <> wrote:
    >
    > > Guys -- this is ridiculous.


    Peter, this is ridiculus. Your thread title includes a general
    statement about the alleged uselessness of auto for functions and when
    presented with counter examples you're not pleased. Sorry, I can't
    give you a "Yes, you're right. auto sucks".

    > Thanks for telling me, that the problem I'm facing does not exist!


    Maybe it doesn't. I yet have to see sample code that looks like it
    makes sense in some context or another. The "simpler" approach you
    asked for would look -- given my AUTO_RETURN macro -- like this:

    template<class T, class U>
    auto func(T x, U y)
    AUTO_RETURN( (x+y)*(x+y)*(x+y) )

    or better yet

    template<class T>
    auto pow3(T z)
    AUTO_RETURN( z*z*z )

    :::
    auto result = pow3(x+y);
    :::

    > I was posting here to publish the unnecessary restrictions in the new C
    > C++ standard and I may have hoped, that somebody may come up with a
    > better method.


    The only thing I would consider an unnecessary is the restriction that
    functions with a single return statement in their body still have to
    define the return type manually because that's but lambdas already
    allow. Beyond that, there might be good technical reasons why things
    are the way they are w.r.t. deduction of return types (I dunno). But
    it actually doesn't bother me that much and *maybe* you're just trying
    to solve problems more complicated than necessary.

    > I mean to say:
    >
    > that somebody may come up with a better method than using macros the
    > way I did...


    I did. My macrro wasn't as ugly as your macro collection. :p
    ;-)

    > I was of the opinion, that my original post contained enough
    > information for all of this.


    I expected you to be more appreciative of the feedback.
    That's life.

    Cheers!
    SG
     
    SG, Jan 19, 2012
    #15
  16. Peter

    Marc Guest

    Juha Nieminen wrote:

    > What exactly is the problem with std::common_type?


    It only works for simple cases. Sure, for types short, unsigned int,
    etc, the type of a-b will be common_type<A,B>::type. But already for
    type char*, a-b has type ptrdiff_t but common_type is char*. If you
    use expression template, every expression will have a different type
    (OTOH, computing (a+b)*(a+b) with expression template instead of first
    evaluating c=a+b then computing c*c is uncommon as it generally means
    the addition is performed twice).

    Since there is a better solution that is guaranteed to always yield
    the right type...
     
    Marc, Jan 19, 2012
    #16
  17. Peter

    Peter Guest

    On Jan 18, 10:48 pm, Juha Nieminen <> wrote:

    >   What exactly is the problem with std::common_type?



    see my earlier post:


    On Jan 18, 9:46 am, Peter <> wrote:
    > In my case
    > decltype(_r0+_r1)
    > maybe different than
    > decltype((_r0+_r1)*(_r0+_r1))
    > which in turn may be different than
    > decltype(std::sin(_r0+_r1))
    > So please tell me how I can avoid having to write the code twice?
     
    Peter, Jan 19, 2012
    #17
  18. Peter

    Peter Guest

    On Jan 19, 1:02 am, SG <> wrote:
    > > On Jan 17, 1:53 pm, Peter <> wrote:

    >
    > > > Guys -- this is ridiculous.

    >
    > Peter, this is ridiculus.  Your thread title includes a general
    > statement about the alleged uselessness of auto for functions and when
    > presented with counter examples you're not pleased.  Sorry, I can't
    > give you a "Yes, you're right. auto sucks".



    counter example?
    The class I'm dealing with has a default constructor.
    So I don't have any advantage in putting the declspec after the
    function header compared to putting it in front and using types
    instead variable names.



    >
    > > Thanks for telling me, that the problem I'm facing does not exist!

    >
    > Maybe it doesn't.  I yet have to see sample code that looks like it
    > makes sense in some context or another.  The "simpler" approach you
    > asked for would look -- given my AUTO_RETURN macro -- like this:
    >
    >   template<class T, class U>
    >   auto func(T x, U y)
    >   AUTO_RETURN( (x+y)*(x+y)*(x+y) )



    The point is to avoid multiple calculation of identical expressions.
    This is so basic that I did not imagine I would have to point it out.
    This is what I'm using variables for.
    So fine -- your "solution" works for trivial functions without
    temporary variables.
    My example problem contained temporary variables -- your solution does
    not apply!


    >
    > or better yet
    >
    >   template<class T>
    >   auto pow3(T z)
    >   AUTO_RETURN( z*z*z )
    >
    >   :::
    >   auto result = pow3(x+y);
    >   :::
    >
    > > I was posting here to publish the unnecessary restrictions in the new C
    > > C++ standard and I may have hoped, that somebody may come up with a
    > > better method.

    >
    > The only thing I would consider an unnecessary is the restriction that
    > functions with a single return statement in their body still have to
    > define the return type manually because that's but lambdas already
    > allow.  Beyond that, there might be good technical reasons why things



    exactly


    > are the way they are w.r.t. deduction of return types (I dunno).  But
    > it actually doesn't bother me that much and *maybe* you're just trying
    > to solve problems more complicated than necessary.



    tell this to my customers!


    >
    > > I mean to say:

    >
    > > that somebody may come up with a better method than using macros the
    > > way I did...

    >
    > I did. My macrro wasn't as ugly as your macro collection. :p
    > ;-)
    >
    > > I was of the opinion, that my original post contained enough
    > > information for all of this.

    >
    > I expected you to be more appreciative of the feedback.
    > That's life.
    >
    > Cheers!
    > SG
     
    Peter, Jan 19, 2012
    #18
  19. Marc <> wrote:
    > It only works for simple cases. Sure, for types short, unsigned int,
    > etc, the type of a-b will be common_type<A,B>::type. But already for
    > type char*, a-b has type ptrdiff_t but common_type is char*.


    std::common_type is intended for combining the parameters using
    arithmetic operations. Exactly what kind of arithmetic operation
    would you combine two char*'s with?

    std::common_type does work properly if the parameters are eg. of
    type std::string or std::complex. I imagine (although I haven't tested)
    the only situation where it won't work properly is when you have two
    different classes (or one clas and one basic type) that can be combined
    with arithmetic operators. OTOH, in these situations it is possible to
    overload std::common_type to make it work.
     
    Juha Nieminen, Jan 20, 2012
    #19
  20. Peter

    Marc Guest

    Juha Nieminen wrote:

    > Marc <> wrote:
    >> It only works for simple cases. Sure, for types short, unsigned int,
    >> etc, the type of a-b will be common_type<A,B>::type. But already for
    >> type char*, a-b has type ptrdiff_t but common_type is char*.

    >
    > std::common_type is intended for combining the parameters using
    > arithmetic operations.


    In special cases, and among other things.

    > Exactly what kind of arithmetic operation
    > would you combine two char*'s with?


    Ever heard of "pointer arithmetic"?

    > std::common_type does work properly if the parameters are eg. of
    > type std::string or std::complex. I imagine (although I haven't tested)
    > the only situation where it won't work properly is when you have two
    > different classes (or one clas and one basic type) that can be combined
    > with arithmetic operators.


    common_type works by looking at the result type of ?:, i.e. basically
    looking at whether one type can be implicitly converted into the
    other. It happens to be useful to determine the result type of
    arithmetic operations on std::duration (and IIRC that was one of the
    reasons why it was created), but note that even there scalar
    multiplication doesn't directly define the result type as the
    common_type of both arguments.

    Now think of the multiplication of 2 matrices: do you expect each
    matrix to be convertible to the result type? In general, do you always
    expect +, -, * and / to return the same type?

    common_type can also be useful in cases where there are no arithmetic
    operations defined.
     
    Marc, Jan 21, 2012
    #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. Daniel Nogradi
    Replies:
    0
    Views:
    395
    Daniel Nogradi
    Nov 15, 2006
  2. Diego Martins
    Replies:
    5
    Views:
    492
    Diego Martins
    Sep 5, 2006
  3. John Goche

    useless function

    John Goche, Nov 20, 2006, in forum: C++
    Replies:
    1
    Views:
    292
    mlimber
    Nov 20, 2006
  4. linkswanted
    Replies:
    1
    Views:
    949
  5. m0shbear
    Replies:
    1
    Views:
    520
    m0shbear
    Mar 19, 2011
Loading...

Share This Page