Constructor question...

T

TDH1978

I have a class where the default constructor is disabled, and the only
constructor takes one parameter. The construction of the object
depends on a condition:

if (cond)
A a(x);
else
A a(y);

The problem is that the object 'a' goes out of scope after the 'if'
statement, and I do not want to use pointers, like:

A* aptr;
if (cond)
aptr = new A(x)
else
aptr = new A(y);


Is there a more elegant solution?
 
L

Luca Risolia

I have a class where the default constructor is disabled, and the only
constructor takes one parameter. The construction of the object depends
on a condition:

if (cond)
A a(x);
else
A a(y);

The problem is that the object 'a' goes out of scope after the 'if'
statement, and I do not want to use pointers, like:

A* aptr;
if (cond)
aptr = new A(x)
else
aptr = new A(y);


Is there a more elegant solution?

You did not define A and the type of cond, x and y, so it's not possible
to give you a general answer. Anyway, see if A a(cond ? x : y) works for
you.
 
Ö

Öö Tiib

I have a class where the default constructor is disabled, and the only
constructor takes one parameter. The construction of the object
depends on a condition:

Better write that also in C++, English is too ambiguous to forward lot
of (possibly important) details.
if (cond)
A a(x);
else
A a(y);

The problem is that the object 'a' goes out of scope after the 'if'
statement, and I do not want to use pointers, like:

A* aptr;
if (cond)
aptr = new A(x)
else
aptr = new A(y);

Is there a more elegant solution?

Multitude. For example separate deciding the argument and constructing a:

AParamType arg = cond ? x : y;

A a(arg);
 
F

Fred Zwarts \(KVI\)

"TDH1978" wrote in message news:[email protected]...
I have a class where the default constructor is disabled, and the only
constructor takes one parameter. The construction of the object depends on
a condition:

if (cond)
A a(x);
else
A a(y);

The problem is that the object 'a' goes out of scope after the 'if'
statement, and I do not want to use pointers, like:

A* aptr;
if (cond)
aptr = new A(x)
else
aptr = new A(y);


Is there a more elegant solution?

A a (cond ? x : y);
 
A

Adam Wysocki

TDH1978 said:
if (cond)
A a(x);
else
A a(y);

Try:

A a(cond ? x : y);

Note that x and y have to be same type, so this will not work:

class B {};
class D1: public B {};
class D2: public B {};

class A
{
public:
A(B) {}
};

void fn(int i)
{
D1 d1;
D2 d2;
A a(i == 5 ? d1 : d2);
}

AW
 
A

Adam Wysocki

TDH1978 said:
The problem is that the object 'a' goes out of scope after the 'if'
statement, and I do not want to use pointers, like:

In other situations and more complex conditions, when you don't want to
use ?: operator, you can consider using auto_ptr.

AW
 
T

Tobias Müller

Adam Wysocki said:
Try:

A a(cond ? x : y);

Note that x and y have to be same type,

That's not true. Essentially, it works if one of the two is convertible to
the type (or a reference of the type) of the other.
(It's actually a bit more complex and sometimes the result is a temporary)
so this will not work:

class B {};
class D1: public B {};
class D2: public B {};

class A
{
public:
A(B) {}
};

void fn(int i)
{
D1 d1;
D2 d2;
A a(i == 5 ? d1 : d2);
}

A a(i == 5 ? (B&)d1 : d2); // Now it works

Tobi
 
A

Adam Wysocki

Tobias Müller said:
That's not true. Essentially, it works if one of the two is convertible to
the type (or a reference of the type) of the other.

Thanks for the clarification.

AW
 
A

Anand Hariharan

That's exactly what the OP said.

The expression involving ternary operator requires that 'x' and 'y' be
of the same type.

Luca Risolia is right in that the OP hasn't provided sufficient
information to give an accurate answer.
 
T

Tobias Müller

Anand Hariharan said:
The expression involving ternary operator requires that 'x' and 'y' be
of the same type.

That's not quite true. One of them has to be convertible to the type of the
other.
Since A has only one constructor, they have to be convertible to a common
type (let's call it Z) anyway. That means, with an appropriate cast on
either x or y, the ternary operator is perfectly suitable for any possible
combination of x, y and Z.
Luca Risolia is right in that the OP hasn't provided sufficient
information to give an accurate answer.

That's where we disagree.

Tobi
 
L

Luca Risolia

That's not quite true. One of them has to be convertible to the type of the
other.
Since A has only one constructor, they have to be convertible to a common
type (let's call it Z) anyway. That means, with an appropriate cast on
either x or y, the ternary operator is perfectly suitable for any possible
combination of x, y and Z.


That's where we disagree.

If you define A (according to the OP's requirements), x and y as
follows, then, although the OP example compiles without problems, "A
a(cond ? x : y);" will not compile:

struct A {
A(int = 0) {};
operator int() {};
};

int main() {
int x;
A y;
A a(true ? x : y); // error: ambiguous
}

source.cpp:9:13: error: conditional expression is ambiguous; 'int' can
be converted to 'A' and vice versa
A a(true ? x : y);

Therefore, as I said, the answer to the OP question in general depends
on the definition of A and the types of x and y, which were not given in
the question.
 
Ö

Öö Tiib

If you define A (according to the OP's requirements), x and y as
follows, then, although the OP example compiles without problems, "A
a(cond ? x : y);" will not compile:

struct A {
A(int = 0) {};
operator int() {};
};

Such class won't pass majority of reviews. Anything that is converting to
arithmetic type silently won't pass. It is close to worst error-prone
thing that C++ can deliver.
int main() {
int x;
A y;
A a(true ? x : y); // error: ambiguous
}

source.cpp:9:13: error: conditional expression is ambiguous; 'int' can
be converted to 'A' and vice versa
A a(true ? x : y);

The error message would perfectly tell the reason why the whole code
should be deleted ... so that is great then. Code deleted, no problem.
 
L

Luca Risolia

Such class won't pass majority of reviews. Anything that is converting to
arithmetic type silently won't pass. It is close to worst error-prone
thing that C++ can deliver.

That's perfectly evident, but it's not relevant to the question. If you
want, you can easily generalize the example to any type; after all,
despite of any reviews, it's quite common to see "lazy" data types
implemented with *implicit* convertions from one type to another one
*and* viceversa. I personally consider that a design flaw, yes, but,
again, this is another issue.
The error message would perfectly tell the reason why the whole code
should be deleted ... so that is great then. Code deleted, no problem.

There is no need to delete the whole code. The solution is to modify the
type by making the convertion in one direction explicit.
Note that in C++11 if you make the operator explicit, "A a (cond ? x :
y)" will compile without modifications.
 
Ö

Öö Tiib

That's perfectly evident, but it's not relevant to the question. If you
want, you can easily generalize the example to any type; after all,
despite of any reviews, it's quite common to see "lazy" data types
implemented with *implicit* convertions from one type to another one
*and* viceversa. I personally consider that a design flaw, yes, but,
again, this is another issue.

My point was that if OP uses that obscure and generally frowned upon
idiom (round-trip implicit conversions) then, yes, you are right
that some of the suggestions that we provide do not compile.

However on that case he likely benefits more from suggestion to stop
using that idiom than from a technique how to construct same object
of such a type in different branches.
There is no need to delete the whole code. The solution is to modify the
type by making the convertion in one direction explicit.
Note that in C++11 if you make the operator explicit, "A a (cond ? x :
y)" will compile without modifications.

There you are correct indeed, I was too harsh in my judgement.
 
J

James Kanze

That's not quite true. One of them has to be convertible to the type of the
other.

That's not quite true either (although it is close enough for
most use). More precisely, one of them has to be implicitly
convertible to the type of the other, *or* one of them must be a
throw expression.

One of the most frustrating consequences of this rule is that:

Base* pb = cond ? new Derived1 : new Derived2;4

doesn't work.
Since A has only one constructor, they have to be convertible to a common
type (let's call it Z) anyway. That means, with an appropriate cast on
either x or y, the ternary operator is perfectly suitable for any possible
combination of x, y and Z.

There's nothing in the original question which indicates whether
the constructor called should be the same or not. If the
constructor ultimately called should be the same.

A a( cond ? x : y );

, possibly with explicit conversions, is fine. Otherwise, if
the class supports copy:

A a ( cond ? A( x ) : A( y ) );

Otherwise, something like:

A const& a = cond ? A( x ) : A( y );

might work, but only for a const reference.

If none of the above work, then the OP will have to use:

std::unique_ptr<A> aptr( cond ? new A( x ) : new A( y ) );
A& a = *aptr;

Unless A is very simple, the cost of the extra allocation is
probably not significant.
 
T

Tobias Müller

James Kanze said:
That's not quite true either (although it is close enough for
most use). More precisely, one of them has to be implicitly
convertible to the type of the other, *or* one of them must be a
throw expression.

You're right of course. The 'implicitly' is important, the throwing not so
in that case.
One of the most frustrating consequences of this rule is that:

Base* pb = cond ? new Derived1 : new Derived2;4

doesn't work.


There's nothing in the original question which indicates whether
the constructor called should be the same or not.

Yes there is. The OP wrote about the only constructor of A, so I assumed
that's the one to be called in both cases.
Unfortunately I snipped that part away.
If the constructor ultimately called should be the same.

A a( cond ? x : y );

, possibly with explicit conversions, is fine. Otherwise, if
the class supports copy:

A a ( cond ? A( x ) : A( y ) );

Otherwise, something like:

A const& a = cond ? A( x ) : A( y );

might work, but only for a const reference.

If none of the above work, then the OP will have to use:

std::unique_ptr<A> aptr( cond ? new A( x ) : new A( y ) );
A& a = *aptr;

Unless A is very simple, the cost of the extra allocation is
probably not significant.

That's difficult to say. One single allocation is certainly not
significant, but if it happens very often or if you use dynamic allocation
everywhere, things look different.

Tobi
 

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,981
Messages
2,570,188
Members
46,731
Latest member
MarcyGipso

Latest Threads

Top