Template deduction: can I encourage compiler to deduce "const"?

Discussion in 'C++' started by Chris Stankevitz, Mar 3, 2013.

  1. Hello,

    Please consider the following example. In the last two lines of
    "main" I specify the first template argument. In particular, I
    specify that the arguments are "const". Is there any way I can get
    the compiler to deduce this so that I do not need to specify it?

    The compiler appears to have "trouble" only when the arguments are
    anonymous.

    FYI I am using gcc 4.6.3.

    Thank you,

    Chris

    // ==========

    struct TSObject {};

    struct TSVisitor
    {
    template<
    class TAMutableOrConstFunctor,
    class TAMutableOrConstObject>
    void Visit(
    TAMutableOrConstFunctor& Functor,
    TAMutableOrConstObject& Object)
    {
    Functor(Object);
    }
    };

    struct TSFunctorMM { void operator()( TSObject& Object)
    {} };
    struct TSFunctorMC { void operator()( TSObject& Object) const
    {} };
    struct TSFunctorCM { void operator()(const TSObject& Object)
    {} };
    struct TSFunctorCC { void operator()(const TSObject& Object) const
    {} };

    int main()
    {
    TSObject Object;

    TSVisitor Visitor;

    TSFunctorMM FunctorMM;
    TSFunctorMC FunctorMC;
    TSFunctorCM FunctorCM;
    TSFunctorCC FunctorCC;

    Visitor.Visit(FunctorMM, Object);
    Visitor.Visit(FunctorMC, Object);
    Visitor.Visit(FunctorCM, Object);
    Visitor.Visit(FunctorCC, Object);

    Visitor.Visit<const TSFunctorMC>(TSFunctorMC(), Object);
    Visitor.Visit<const TSFunctorCC>(TSFunctorCC(), Object);

    return 0;
    }
     
    Chris Stankevitz, Mar 3, 2013
    #1
    1. Advertising

  2. On Sun, 03 Mar 2013 00:12:17 -0800, Chris Stankevitz wrote:

    > Hello,
    >
    > Please consider the following example. In the last two lines of "main"
    > I specify the first template argument. In particular, I specify that
    > the arguments are "const". Is there any way I can get the compiler to
    > deduce this so that I do not need to specify it?
    >
    > The compiler appears to have "trouble" only when the arguments are
    > anonymous.


    The compiler has no trouble at all in deducing the template parameters.
    The trouble starts at the next step, where the compiler finds that you
    try to bind an rvalue to a non-const lvalue reference and it balks at
    that.

    The two solutions that I can think of to resolve this issue are
    1. Pass the functor by value (con: changes to a state-full functor will
    not be visible in the caller)
    2. Pass the functor by rvalue reference (con: your compiler has to
    support it.)

    >
    > FYI I am using gcc 4.6.3.
    >
    > Thank you,
    >
    > Chris
    >

    Bart v Ingen Schenau
     
    Bart van Ingen Schenau, Mar 3, 2013
    #2
    1. Advertising

  3. Chris Stankevitz

    jz bnk Guest

    On Sunday, March 3, 2013 1:12:17 AM UTC-7, Chris Stankevitz wrote:
    > Hello,
    >
    >
    >
    > Please consider the following example. In the last two lines of
    >
    > "main" I specify the first template argument. In particular, I
    >
    > specify that the arguments are "const". Is there any way I can get
    >
    > the compiler to deduce this so that I do not need to specify it?
    >
    >
    >
    > The compiler appears to have "trouble" only when the arguments are
    >
    > anonymous.


    Possibly – however, is there some reason why you can't use rvalue references
    here? Search “universal reference” if you're not familiar with that idiom
    (don't particularly like that name myself, but it's what we've got... :)
     
    jz bnk, Mar 3, 2013
    #3
  4. On Mar 3, 12:34 am, jz bnk <> wrote:
    > Possibly – however, is there some reason why you can't use rvalue references
    > here?  Search “universal reference”


    Thank you. I have never used a universal reference but I know what
    they are and can use one here.

    Thank you,

    Chris
     
    Chris Stankevitz, Mar 3, 2013
    #4
  5. On Mar 3, 12:34 am, Bart van Ingen Schenau
    <> wrote:
    > The compiler has no trouble at all in deducing the template parameters.
    > The trouble starts at the next step, where the compiler finds that you
    > try to bind an rvalue to a non-const lvalue reference


    Hello,

    Thank you for your reply. I think you are trying to make these
    points:

    1. The compiler is presented with an rvalue and the opportunity to
    "deduce" that rvalue into
    a) a mutable lvalue reference
    or
    b) a const lvalue reference

    2. The compiler is choosing (a).

    3. (a) is a reasonable deduction for the compiler to make.

    4. If I want (b) I will need to use explicit template arguments or
    universal references.

    Thank you,

    Chris
     
    Chris Stankevitz, Mar 3, 2013
    #5
  6. Chris Stankevitz

    SG Guest

    On Mar 3, 9:12 am, Chris Stankevitz wrote:
    > Hello,
    >
    > Please consider the following example.  In the last two lines of
    > "main" I specify the first template argument.  In particular, I
    > specify that the arguments are "const".  Is there any way I can get
    > the compiler to deduce this so that I do not need to specify it?


    Why? What problem are you trying to solve?

    > // ==========
    >
    > struct TSObject {};
    >
    > struct TSVisitor
    > {
    >   template<
    >     class TAMutableOrConstFunctor,
    >     class TAMutableOrConstObject>
    >   void Visit(
    >     TAMutableOrConstFunctor& Functor,
    >     TAMutableOrConstObject& Object)
    >   {
    >     Functor(Object);
    >   }
    > };
    >
    > struct TSFunctorMM { void operator()(      TSObject& Object)
    > {} };
    > struct TSFunctorMC { void operator()(      TSObject& Object) const
    > {} };
    > struct TSFunctorCM { void operator()(const TSObject& Object)
    > {} };
    > struct TSFunctorCC { void operator()(const TSObject& Object) const
    > {} };
    >
    > int main()
    > {
    >   TSObject Object;
    >
    >   TSVisitor Visitor;
    >
    >   TSFunctorMM FunctorMM;
    >   TSFunctorMC FunctorMC;
    >   TSFunctorCM FunctorCM;
    >   TSFunctorCC FunctorCC;
    >
    >   Visitor.Visit(FunctorMM, Object);
    >   Visitor.Visit(FunctorMC, Object);
    >   Visitor.Visit(FunctorCM, Object);
    >   Visitor.Visit(FunctorCC, Object);
    >
    >   Visitor.Visit<const TSFunctorMC>(TSFunctorMC(), Object);
    >   Visitor.Visit<const TSFunctorCC>(TSFunctorCC(), Object);


    I understand that you want this to "work" without having to specify
    such a template parameter. But what does "work" actually mean here?
    You should be more specific as to what kind of behaviour you are
    shooting for.

    Here's an idea:

    struct TSVisitor
    {
      template<
        class TAMutableOrConstFunctor,
        class TAMutableOrConstObject >
      void Visit(
        TAMutableOrConstFunctor && Functor,
        TAMutableOrConstObject && Object )
      {
    std::forward<const TAMutableOrConstFunctor>(Functor)(
    std::forward<const TAMutableOrConstObject>(Object)
    );
      }
    };

    forward<const T>(param) allows non-const lvalues to be modified while
    rvalues are always forwarded as const. If you don't want to restrict
    access to rvalues like that you can simply remove "const":
    forward<T>(param). I just added the const here because it looks like
    you don't want temporaries to be mutable. But removing it might lead
    to more efficient code since you can possibly leverage move-semantics-
    like optimizations.
     
    SG, Mar 3, 2013
    #6
  7. On Mar 3, 1:32 am, SG <> wrote:
    > Why? What problem are you trying to solve?


    My short term goal:

    Get the original-post code to compile without specifying the template
    argument. Your universal reference trick fixed this, thank you for
    that help. However, I'm not sure why you specify "const" in the
    template argument to std::forward. I'm not sure why you wouldn't
    either. I just don't know about that. It seems since I sometimes
    want to treat the universal reference as an lvalue that I would not
    type 'const' anywhere.

    My medium term goal:

    I have a functor and an object. The functor wants to be passed some
    parameter that is derived from the object. A "third party
    intermediary" is
    1. taking the functor and object
    2. using the object to produce yet another "third party object"
    3. pass the derived "third party object" to the functor

    The difficulty is that the third party doesn't know if the object
    should be a const reference or a mutable reference. And it doesn't
    know whether the functor should be a const reference or a mutable
    reference. I'm having trouble incorporating this concept into my
    simple original post example. So you can look at...

    My medium long term goal:

    To statically store and retrieve the characteristics of a class's
    members. For more info and a link to the github source you can jump
    in to the thread here:

    http://lists.boost.org/boost-users/2013/03/77972.php

    My long term goals:

    to make money, remodel my kitchen, make my wife happy, make me happy.
    That's what all this really boils down to. My selfish desire to be
    happy.

    Thanks again,

    Chris

    ===
     
    Chris Stankevitz, Mar 3, 2013
    #7
  8. On Sun, 03 Mar 2013 01:14:40 -0800, Chris Stankevitz wrote:

    > On Mar 3, 12:34 am, Bart van Ingen Schenau
    > <> wrote:
    >> The compiler has no trouble at all in deducing the template parameters.
    >> The trouble starts at the next step, where the compiler finds that you
    >> try to bind an rvalue to a non-const lvalue reference

    >
    > Hello,
    >
    > Thank you for your reply. I think you are trying to make these points:
    >
    > 1. The compiler is presented with an rvalue and the opportunity to
    > "deduce" that rvalue into
    > a) a mutable lvalue reference
    > or
    > b) a const lvalue reference


    Actually, the deduction process is slightly different.
    - You have a function taking a TAFunctor& (with TAFunctor a template
    parameter). As the function parameter is of reference type, the deduction
    is done for the referenced type (TAFunctor).
    - In the call, the function is provided with a value of TSFunctorMC
    - Deduction is straightforward: TAFunctor is deduced as TSFunctorMC
    - Deduction succeeds, so there is no reason to try additional options
    (such as adding const-qualification or trying base/derived classes)

    The problem you are encountering is that a rvalue of type T is itself
    _not_ const qualified.

    >
    > 4. If I want (b) I will need to use explicit template arguments or
    > universal references.


    That is right. For the use-case you described in another post in the
    thread, a universal reference seems the most appropriate choice.

    >
    > Thank you,
    >
    > Chris


    Bart v Ingen Schenau
     
    Bart van Ingen Schenau, Mar 4, 2013
    #8
    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. Dan Krantz
    Replies:
    3
    Views:
    438
    Howard Hinnant
    Jun 13, 2006
  2. Javier
    Replies:
    2
    Views:
    585
    James Kanze
    Sep 4, 2007
  3. Fei Liu
    Replies:
    0
    Views:
    432
    Fei Liu
    Oct 25, 2007
  4. Fei Liu
    Replies:
    4
    Views:
    801
    Victor Bazarov
    Oct 26, 2007
  5. nguillot
    Replies:
    5
    Views:
    539
Loading...

Share This Page