这是有效的 C ++ ,假设我想将参数变量复制到成员变量:
struct Struct {
Struct(const T& value) : value(value) {}
T value;
};
(更新:它在Visual Studio中有效,但仍然可能依赖于编译器) (预期问题:为什么需要这个?答案:制作宏观目的)
答案 0 :(得分:3)
这确实是有效的代码,就像其他答案一样,我会警告你应该非常小心地使用它,因为它可能会让人感到困惑,并可能导致很难维护代码。
那么为什么这样呢?如果我们考虑你的构造函数:
Struct(const T& value) : value(value) {}
^ ^
1 2
1
和2
在不同的范围内进行评估。因此,我们需要查看draft C++ standard部分12.6.2
初始化基础和成员并查看一些语法:
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
消化后,我们发现1
实际上是 mem-initializer-id ,而2
是 expression-listopt ,我们可以分别转到段落 2 和 12 。段落 2 说:
在mem-initializer-id中,在构造函数的类的范围内查找初始的非限定标识符,如果在该范围内找不到,则在包含构造函数定义的范围中查找它。 [...]
首先我们会在课堂上查找1
,而我们可以从段落 12 中看到:
mem-initializer的expression-list或braced-init-list中的名称在指定了mem-initializer的构造函数的范围内进行计算。
2
将在构造函数的范围内查找。因此1
将首先找到成员变量并停止查找2
将在构造函数中查找并找到参数。这也意味着如果您想在表达式列表中引用成员变量,则必须使用 this-> 。
答案 1 :(得分:2)
是。它确实编译。对于编译器,没有任何歧义value
是哪个。
#include <iostream>
using namespace std;
template <typename T>
struct Struct {
Struct(const T & value) : value(value) {}
T value;
};
int main() {
Struct<int> T(1);
// your code goes here
return 0;
}
但是多次声明,程序员破译并不容易。它确实有效,因为对于编译器,参数掩盖了成员函数,因此value
中的第二个value(value)
是参数,但因为只有成员和祖先类可以位于{{1}的左侧部分},它确实引用了这里的成员。
足以使调试和维护变得复杂。
答案 2 :(得分:2)
这是有效的,但在某些圈子中是不明智的,包括我的圈子。
在某种意义上它是有效的,成员变量将根据您的需要由参数正确设置。执行初始化程序列表后,将隐藏该成员。对value
的任何引用都将访问该参数。这可能是一件坏事。
出于两个原因,这是不明智的。首先,可维护性和混乱。看到参数和成员变量具有相同的名称是不常见的。因此,大多数程序员必须停下来并思考这意味着什么。毕竟,你做到了。请记住,代码首先为程序员编写,其次是编译器。易于理解的代码比难以理解的代码要好得多。在代码审查中,我会基于这些理由拒绝此代码。
其次,在大多数情况下,成员隐藏可能会成为一个问题。
我建议提出一个理智的命名方案并坚持下去。 “Sane”表示参数永远不能与成员变量同名。例如,在我的命名方案中,成员变量总是以m
为前缀 - 参数永远不会被添加。所以在这个方案中你的代码将成为:
struct Struct {
Struct(const T& value) : mValue(value) {}
T mValue;
};
使用这个方案,没有人对这里发生的事情感到困惑,没有人要问StackOverflow“这是合法的吗?”
答案 3 :(得分:2)
这是C ++标准允许的,但考虑在初始化成员之后,您希望在函数中执行更多工作的情况。例如,使用3
代表更有意义的计算:
class Foo
{
public:
int bar;
Foo(int bar) : bar(bar) { bar = 3; }
};
函数中的赋值会更改参数bar
的值,而不会更改成员bar
的值。在您的示例中不会发生这种情况,因为您使用const
声明了参数。因此,如果您确定始终使用const
声明参数,则会受到保护。但考虑一个更复杂的情况:
class Foo
{
public:
int bar;
int baz;
void AuxiliaryFunction() { bar = 3; }
Foo(const int &bar) : bar(bar)
{
AuxiliaryFunction();
baz = bar;
}
};
在此示例中,成员bar
通过构造函数中调用的另一个函数获得一些值。然后,作业baz = bar;
可能会复制成员bar
,但它实际上会复制参数bar
。
所以,虽然这是合法的C ++,但应该明智地使用它。
答案 4 :(得分:1)
有效。但是有一点警告:更改参数名称和代码是未定义的行为。
template <typename T>
struct Struct {
Struct(const T & argument) : value(value) {}
T value;
};
答案 5 :(得分:0)
这是有效的,但正如需要提出这一点所证明的那样,可能会引起混乱和混乱。
长期存在的问题是出现了两个截然不同的名称。
我喜欢这样做(但有些人讨厌它):
struct Struct {
Struct(const T& newValue) : value(newValue) {}
T value;
};