【问题标题】:same identifier for type and object in declaration声明中类型和对象的相同标识符
【发布时间】:2018-01-12 04:20:15
【问题描述】:

我偶然发现了一个函数实现,它为相同类型的参数回收类型名称。代码编译并且似乎完全符合预期。这是一个最小化的版本:

#include <iostream>

using namespace std;

struct X {
    int v;
};

void print_X(const X& X)   // <--- here the identifier X has *two different meanings*
{
    cout << "X.v:" << X.v << endl;
}

代码是针对 Borland C++ 5.6.4 开发的

我尝试了几种不同且更新的编译器:

所有人都接受它而不抱怨。

我不认为它是好的 C++,但是...

它是有效的 C++ 吗?如果是,将来是否有效?

更新

多么可怕!直到现在我才明白,对于简单的变量声明也是如此:

X X;

演示:http://ideone.com/a9GM49

更新 #2

C++ 与 C 语言共享此功能:

#include <stdio.h>

typedef struct X {
    int v;
} X;

int main()
{
    X X;
    X.v = 7;
    printf("X.v:%d\n", X.v);
    return 0;
}

演示:http://ideone.com/nheZTa

【问题讨论】:

  • 它是有效的 C++。 C++ 是否好还有待商榷。
  • @Ron 我有一种强烈的感觉,那就是它可能真的很糟糕,tried to illustrate that

标签: c++ c naming-conventions variable-declaration function-definition


【解决方案1】:

通过这样做,您将全局名称隐藏在功能块内。

void print_X(const X& X, const X& Y)  //won't compile

void print_X(const X& X){
   X myX;    //again, won't compile
}

用 Stroustrup 的话来说:*

块中的名称声明可以隐藏块中的声明 封闭块或全局名称。也就是说,可以将名称重新定义为 引用块内的不同实体。从街区出来后, 这个名字恢复了它以前的意思。


* Stroustrup:C++ 编程语言,第 4 版;第 6.3.4 节范围;第 157 页

【讨论】:

  • 我认为上面的代码不能很好地说明隐藏的不良影响,因为它不编译。它也可以有nice side effects
  • 除了示例之外,您可以添加引用的链接吗?我再次阅读了您的答案,发现引用部分很有用(代码有时也会分散注意力)。我试图找到来源,但没有运气。能否请您添加引用的链接,然后我想为它投票...
  • C++ Programming Stroustrup 第 4 版书籍节选
  • 谢谢。可以加章节和页码吗?
  • 第 6.3.4 节范围;第 157 页
【解决方案2】:

有效。它从外部范围隐藏变量。像这样隐藏通常称为 shadowing,并且您的编译器可能有一个警告,您可以启用它来告诉您何时发生(gcc 有 -Wshadow)。

这是另一个例子:

int x; // global variable - always accessible as ::x
int main(int x, char** argv) { // this 'x' hides global 'x'
    // This is the only place you can get at the argument 'x'
    // before it is hidden by the line below.
    int x; // this subsequently hides the function argument 'x'
    {
        int x; // hides the 'x' at function scope
        for (int x = 0; x < 42; ++x) { // this 'hides 'x' in our nested scope
            // The for loop induction variable 'x' is what's in scope here
        }
        // Now 'x' is again the nested-scope 'x'
    }
    // Here 'x' again refers to the function scope 'x'
}
// At any point in time you can get access to the 'x' that is directly
// in scope *or* the global 'x' (as '::x')
// But you cannot access the other 'x's until you are back in
// their respective scopes.

但尽量避免做上述的事情。它很快就会导致混乱和错误。

【讨论】:

  • 好的,这演示了对象的隐藏。但是,隐藏交易通常与标识符有关。
  • 了解术语 shadowing 和开关 -Wshadow 绝对有帮助,但有趣的是 names are hidden,而不仅仅是 变量 -- 在对象名称隐藏类型名称之后代码可能会改变其含义的事实非常令人困惑......
【解决方案3】:

是的,它是有效的。您正在内部范围内声明一个变量(参数),该变量(参数)对外部范围隐藏了名称。

在这种情况下当然不是一个好主意。

【讨论】:

  • 讽刺的是:它阻止你使用相同类型的第二个参数,所以你不能在函数调用中混合它们;-)
  • 我发现很难找到一个可读的参考。而且,我只是看到它:X X; 似乎也是有效的。相应地更新了我的问题。
  • 我还发现struct X { int v; }; X X; 是有效代码。所以隐藏名称似乎不限于范围更改...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-15
  • 1970-01-01
  • 2011-01-02
  • 1970-01-01
  • 1970-01-01
  • 2013-10-12
相关资源
最近更新 更多