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)
There's no problem with giving parameter names and instance variable names the same name.
The caller's arguments passed to the function's parameters do not have to have the same names.
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.
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).
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->.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With