Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is using same parameter name and member name valid

Is this valid C++, assuming I want to copy the argument variable to the member variable:

struct Struct {
  Struct(const T& value) : value(value) {}
  T value;
};

(Update: It works in Visual Studio, but still that might be compiler dependent) (Expected question: Why do you need this? Answer: Macro-making purposes)

like image 301
Viktor Sehr Avatar asked Dec 16 '13 15:12

Viktor Sehr


People also ask

Can parameters have the same name?

There's no problem with giving parameter names and instance variable names the same name.

Do parameter names and argument names have to be the same?

The caller's arguments passed to the function's parameters do not have to have the same names.

Can parameter have same name as variable?

Answer. When a parameter has the same name as a variable defined outside, instead of the function using the variable defined outside, it will only reference the value that was passed to the parameter. So, parameters will be used over variables of the same name within a function.

Can a function have a parameter with the same name as a global variable?

Yes it works like this as variables of same names are allowed provided that they are in different scopes. "x" is both defined in global scope (global variable) and a local scope (in foo() as a parameter).


2 Answers

This is indeed valid code and like the rest of the answers I will warn you that this should be used very carefully since it can be confusing and would probably lead to hard to maintain code.

So why does this work? If we consider your constructor:

Struct(const T& value) : value(value) {}
                         ^     ^
                         1     2    

1 and 2 are evaluated in different scopes. So we need to look at the draft C++ standard section 12.6.2 Initializing bases and members and look at some grammar:

ctor-initializer:
    : mem-initializer-list 
mem-initializer-list:
    mem-initializer ...opt
    mem-initializer , mem-initializer-list ...opt
mem-initializer:
    mem-initializer-id ( expression-listopt )
    mem-initializer-id braced-init-list

After digesting this we see that 1 is really a mem-initializer-id and 2 is a expression-listopt and we can go to paragraph 2 and 12 respectively for each of these. Paragraph 2 says:

In a mem-initializer-id an initial unqualified identifier is looked up in the scope of the constructor’s class and, if not found in that scope, it is looked up in the scope containing the constructor’s definition. [...]

So 1 will be looked up in the class first while we can see from paragraph 12 which says:

Names in the expression-list or braced-init-list of a mem-initializer are evaluated in the scope of the constructor for which the mem-initializer is specified.

2 will be looked up in the scope of the constructor. So 1 will find the member variable first and stop looking while 2 will look in the constructor and find the parameter. This also means that if you wanted to refer to a member variable in an expression-list you would have to use this->.

like image 121
Shafik Yaghmour Avatar answered Oct 05 '22 23:10

Shafik Yaghmour


It is perfectly valid, standard-conformant code, beyond any doubt.

Struct(const T& value) : value(value) {}
                               ^^^^^ this is argument
                         ^^^^^ this is the member

Now the question is: is this good practice? In my opinion, NO. I prefer my data-members to follow different yet consistent naming convention, such as data-members always start with _. So I would prefer this:

Struct(const T& value) : _value(value) {}

where _value is data member. You could follow any naming convention — just make sure that you're consistent.

Note that in your code variable, functions, classes or any identifier should not start with double underscore such as __value, or single underscore followed by upper case letter such as _Value — such names are reserved for implementations.

like image 34
Nawaz Avatar answered Oct 06 '22 01:10

Nawaz