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

  • Thread starter Chris Stankevitz
  • Start date
C

Chris Stankevitz

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;
}
 
B

Bart van Ingen Schenau

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
 
J

jz bnk

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... :)
 
C

Chris Stankevitz

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
 
C

Chris Stankevitz

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
 
S

SG

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.
 
C

Chris Stankevitz

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

===
 
B

Bart van Ingen Schenau

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top