Scoping in initializer list

H

Ham Pastrami

class Point {
public:
const int x, y;
Point(int x, int y);
}

Point::point(int x, int y) : x(x), y(y)
{
}

This compiles with MSVC and the data seems correct at runtime, but is this
code safe or is it compiler-dependent? It seems ambiguous that the
initializer list is using member_x and arg_x at the same time. More
specifically, what should happen when

Point::point(int x, int y) : x(x+1), y(x+y)

the initializer for y could be reasonably interpreted as either (member_x+y)
or (arg_x+y)?
 
M

Michael Ashton

Ham said:
class Point {
public:
const int x, y;
Point(int x, int y);
}

Point::point(int x, int y) : x(x), y(y)
{
}

This compiles with MSVC and the data seems correct at runtime, but is this
code safe or is it compiler-dependent? It seems ambiguous that the
initializer list is using member_x and arg_x at the same time. More
specifically, what should happen when

Point::point(int x, int y) : x(x+1), y(x+y)

the initializer for y could be reasonably interpreted as either (member_x+y)
or (arg_x+y)?

This might work, but it's bad naming. The constructor arguments should
have different names from the class members (or vice-versa).

As I understand the standard, this should compile and run as you
expect. Member initialiser lists are special; only base classes and
class members can be mentioned in them, so names of initialisers are
only searched for among those lists.

But arguments for initialisers can be a wider range of things,
including (of course) the arguments to the constructor. In this case,
the constructor arguments are in the narrower scope, so they shadow the
class members.

Nevertheless, it's confusing to read, and bad practice.

--mpa
 
J

John Carson

Ham Pastrami said:
class Point {
public:
const int x, y;
Point(int x, int y);
}

Point::point(int x, int y) : x(x), y(y)
{
}

This compiles with MSVC and the data seems correct at runtime, but is
this code safe or is it compiler-dependent? It seems ambiguous that
the initializer list is using member_x and arg_x at the same time.
More specifically, what should happen when

Point::point(int x, int y) : x(x+1), y(x+y)

the initializer for y could be reasonably interpreted as either
(member_x+y) or (arg_x+y)?


This is covered in Section 12.6.2/7 of the Standard. In looking up
initializers, the constructor's arguments hide class members. If there are
no constructor arguments matching the initializer name, then class members
are looked up. Thus y(x+y) is y(arg_x+arg_y).

Formally,

"Names in the expression-list [i.e., the arguments of the items in the
initializer list] of a mem-initializer are evaluated in the scope of the
constructor for which the mem-initializer is specified."

So think what would happen in the body of a constructor. In the body of the
constructor (as with any other member function), function arguments hide
class members of the same name. Thus function arguments do the same when
used to initialize member variables.

I agree with Michael Ashton, however, that such code is bad style.
 
W

White Wolf

John Carson wrote:
[SNIP]
So think what would happen in the body of a constructor. In the body of
the constructor (as with any other member function), function arguments
hide class members of the same name. Thus function arguments do the same
when used to initialize member variables.

I agree with Michael Ashton, however, that such code is bad style.

Some call it job safety. :)
 

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,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top