C++0x "auto" equivalence in non-0x? (function needs to return undeterminedtype value)

Q

Qi

What I want to do is,

template <typename T>
void process(const T & value);

UndeterminedType generate();

"generate" may return value in various types, which is unknown when it's
called. What's determined is that all types are already known and
defined.
So I know "generate" can return a value in type A, B or C, but I don't
know which one it exactly is.

The result from "generate" is only used to feed "process", I don't need
to store it. But it will be good if I can store it.

Seems "auto" keyword in C++0x is introduced to solve that problem.

My question is, how to do the equivalence in non-0x C++?

The reason I won't use 0x is seems current compilers can't support it
well. VC only supports "auto" from version 10 while I'm using 9!
 
M

m0shbear

What I want to do is,

template <typename T>
void process(const T & value);

UndeterminedType generate();

"generate" may return value in various types, which is unknown when it's
called. What's determined is that all types are already known and
defined.
So I know "generate" can return a value in type A, B or C, but I don't
know which one it exactly is.

The result from "generate" is only used to feed "process", I don't need
to store it. But it will be good if I can store it.

Seems "auto" keyword in C++0x is introduced to solve that problem.

My question is, how to do the equivalence in non-0x C++?

The reason I won't use 0x is seems current compilers can't support it
well. VC only supports "auto" from version 10 while I'm using 9!

Why not make generate a template function and call generate<T>(...)?
 
Q

Qi

Why not make generate a template function and call generate<T>(...)?

Because T is undetermined when calling "generate".
Your that kind of template function needs T to be determined.
 
J

Joshua Maurice

Because T is undetermined when calling "generate".
Your that kind of template function needs T to be determined.

This can be a very hard problem to solve. I've looked through the
large and hacky codebase in boost that tries to support pseudo-lambda
functions with its _1, _2, and _3. This is an impossible problem to
solve in all cases, a pain in the ass for suitably general cases, and
maybe doable for easy cases. I would need to know specific details to
offer further advice, though I would suggest reworking it so you don't
have this requirement if at all reasonable.
 
Q

Qi

This can be a very hard problem to solve. I've looked through the
large and hacky codebase in boost that tries to support pseudo-lambda
functions with its _1, _2, and _3. This is an impossible problem to
solve in all cases, a pain in the ass for suitably general cases, and
maybe doable for easy cases. I would need to know specific details to
offer further advice, though I would suggest reworking it so you don't
have this requirement if at all reasonable.

Yes, if there is no solution, I will change my design, not very
difficult but it will be a little ugly.

Don't know what details you need.
I would give some pseudo code to explain more.

struct A { void run() const; };
struct B { void run() const; };
struct C { void run() const; };

template <typename T>
void process(const T & value);
{
value.run();
}

/*****************************
How to deal with SomeType?
In C++0x, it can be "auto" (hope I'm correct,
I never tried 0x though),
But how to do it in non-0x?
*****************************/
SomeType generate()
{
switch(random number) {
case 0:
return A();

case 1:
return B();

default:
return C();
}
}

void main()
{
process(generate()); // here is how I want to use "generate"
}
 
K

Kai-Uwe Bux

Qi said:
What I want to do is,

template <typename T>
void process(const T & value);

UndeterminedType generate();

"generate" may return value in various types, which is unknown when it's
called. What's determined is that all types are already known and
defined.
So I know "generate" can return a value in type A, B or C, but I don't
know which one it exactly is.

The result from "generate" is only used to feed "process", I don't need
to store it. But it will be good if I can store it.

Seems "auto" keyword in C++0x is introduced to solve that problem.

I thought, the "auto" keyword will still require that the compiler can
deduce the type at compile time.
My question is, how to do the equivalence in non-0x C++?

The reason I won't use 0x is seems current compilers can't support it
well. VC only supports "auto" from version 10 while I'm using 9!


Best,

Kai-Uwe Bux
 
S

SG

/*****************************
How to deal with SomeType?
In C++0x, it can be "auto" (hope I'm correct,
I never tried 0x though),
But how to do it in non-0x?
*****************************/
SomeType generate()
{
   switch(random number) {
     case 0:
          return A();

     case 1:
          return B();

     default:
          return C();
   }
}

It seems you misunderstood 'auto'. There is nothing dynamic about
'auto'. For functions, 'auto' is part of the new function declaration
syntax:

double foo(int,string); // old syntax (still valid)
auto foo(int,string) -> double; // new syntax

The only difference is that the return type is mentioned last in the
declaration.
void main()
{
   process(generate()); // here is how I want to use "generate"
}

This cannot work, neither in C++0x nor in C++98. generate must have
some return type known at compile time. You want to change the type at
runtime. But template argument deduction happens at compile-time. So,
you would need some kind of type-erasing wrapper (boost::variant) and
manually perform some kind of dispatch to select the correct process
function. You can't magically use a runtime type information to select
the right process function at compile-time.

SG
 
K

Kai-Uwe Bux

Qi said:
Yes, if there is no solution, I will change my design, not very
difficult but it will be a little ugly.

Don't know what details you need.
I would give some pseudo code to explain more.

struct A { void run() const; };
struct B { void run() const; };
struct C { void run() const; };

template <typename T>
void process(const T & value);
{
value.run();
}

/*****************************
How to deal with SomeType?
In C++0x, it can be "auto" (hope I'm correct,
I never tried 0x though),
But how to do it in non-0x?
*****************************/
SomeType generate()
{
switch(random number) {
case 0:
return A();

case 1:
return B();

default:
return C();
}
}

void main()
{
process(generate()); // here is how I want to use "generate"
}

It seems that the above could be rewritten as:

struct A { void run() const; };
struct B { void run() const; };
struct C { void run() const; };

template <typename T>
void process(const T & value);
{
value.run();
}

void generate()
{
switch(random number) {
case 0: {
A x;
process(x);
}
case 1: {
B x;
process(x);
}
default: {
C x;
process(x);
}
}
}

int main()
{
generate();
}


Alternatively, you could make A, B, C inherit from a common base and make
run() a virtual method. You could also use duck typing: keep A, B, and C
unrelated but provide a class Runnable that can accommodate values of A, B,
and C:

#include <algorithm>
using std::swap;

class Runnable {

struct base {

virtual
~base ( void ) {}

virtual
void run ( void ) {}

virtual
base * clone ( void ) {}

};

template < typename A >
struct derived : base {

A data;

derived ( A const & a )
: data ( a )
{}

virtual
void run ( void ) {
data.run();
}

virtual
derived * clone ( void ) {
return ( new derived ( data ) );
}

};

base * the_ptr;

public:

template < typename A >
Runnable ( A const & a )
: the_ptr( new derived<A>( a ) )
{}

Runnable ( Runnable const & other )
: the_ptr ( other.the_ptr->clone() )
{}

~Runnable ( void ) {
delete ( the_ptr );
}

friend
void swap ( Runnable & lhs, Runnable & rhs ) {
swap( lhs.the_ptr, rhs.the_ptr );
}

Runnable & operator= ( Runnable other ) {
swap( *this, other );
return ( *this );
}

void run ( void ) {
the_ptr->run();
}

};


#include <iostream>
#include <ostream>

struct A {

void run ( void ) {
std::cout << "A\n";
}

};

struct B {

void run ( void ) {
std::cout << "B\n";
}

};

Runnable generate ( int i ) {
if ( i % 2 ) {
return ( A() );
} else {
return ( B() );
}
}

int main ( void ) {
for ( int i = 0; i < 10; ++i ) {
generate(i).run();
}
}


Best,

Kai-Uwe Bux
 
Q

Qi

This cannot work, neither in C++0x nor in C++98. generate must have
some return type known at compile time. You want to change the type at
runtime. But template argument deduction happens at compile-time. So,
you would need some kind of type-erasing wrapper (boost::variant) and
manually perform some kind of dispatch to select the correct process
function. You can't magically use a runtime type information to select
the right process function at compile-time.

Seems I was confused by the runtime behavior in function "generate".

Now I get it.

I will have to "process" manually for corresponding type.
 
Q

Qi

Alternatively, you could make A, B, C inherit from a common base and make
run() a virtual method. You could also use duck typing: keep A, B, and C
unrelated but provide a class Runnable that can accommodate values of A, B,
and C:

I would like avoid virtual functions since the processing are quite
cpu intensive.

I would prefer compile time polymorphism over runtime virtual functions.
 
M

m0shbear

I would like avoid virtual functions since the processing are quite
cpu intensive.

I would prefer compile time polymorphism over runtime virtual functions.

Boost::any isn't virtual. But you have to try-catch bad casts to infer
type.
 
J

Johannes Schaub

Qi said:
What I want to do is,

template <typename T>
void process(const T & value);

UndeterminedType generate();

"generate" may return value in various types, which is unknown when it's
called. What's determined is that all types are already known and
defined.
So I know "generate" can return a value in type A, B or C, but I don't
know which one it exactly is.

The result from "generate" is only used to feed "process", I don't need
to store it. But it will be good if I can store it.

Seems "auto" keyword in C++0x is introduced to solve that problem.

Looks like you are confused. "auto" has nothing to do with that. What you
want to use is a boost::variant<A, B, C> or equivalent.
 
J

Johannes Schaub

m0shbear said:
Boost::any isn't virtual. But you have to try-catch bad casts to infer
type.

That's plain wrong. boost::any performs type-erasure, and needs runtime
polymorphism to remember the dynamic type of the stored object. It uses
virtual functions (clone, etc..).

boost::any is inefficient, and is designed to be *simple*. It doesn't do
stack-allocation, so it will also use the heap.
 
M

Marcel Müller

Hi,
I would like avoid virtual functions since the processing are quite
cpu intensive.

oh, you are counting clock cycles. Hopefully you counted the right ones.
I would prefer compile time polymorphism over runtime virtual functions.

Anyway, you will never be able to use compile time polymorphism if the
type decision is taken at run time (in the generate function).


Marcel
 
J

James Kanze

What I want to do is,
template <typename T>
void process(const T & value);
UndeterminedType generate();
"generate" may return value in various types, which is unknown when it's
called. What's determined is that all types are already known and
defined.
So I know "generate" can return a value in type A, B or C, but I don't
know which one it exactly is.
The result from "generate" is only used to feed "process", I don't need
to store it. But it will be good if I can store it.
Seems "auto" keyword in C++0x is introduced to solve that problem.

No. "auto" is purely a compile time analysis. As are
templates. The only question is what type "generate" is
declared to return.
 
M

m0shbear

That's plain wrong. boost::any performs type-erasure, and needs runtime
polymorphism to remember the dynamic type of the stored object. It uses
virtual functions (clone, etc..).

boost::any is inefficient, and is designed to be *simple*. It doesn't do
stack-allocation, so it will also use the heap.

My bad. I'm still somewhat of a n00b when it comes to boost. In
hindsight, I should've said boost::variant, as boost::any looks like a
dynamic_cast-checked conversion from void*.
 

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

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,144
Latest member
KetoBaseReviews
Top