name collision in C++

怎甘沉沦 提交于 2019-12-23 20:32:05

问题


While writing some code i came across this issue:


#include <iostream>

class random { public: random(){ std::cout << "yay!! i am called \n" ;} };

random r1 ;

int main() { std::cout << "entry!!\n" ; static random r2; std::cout << "done!!\n" ; return 0 ; }

When i try to compile this code i get the error
error: ârandomâ does not name a type.
When I use some different name for the class the code works fine.
Seems like random is defined somewhere else(although the compiler message is not very informative).

My question is how can i assure that a name i am using doesn't collides with a name used in included files. I have tried using namespaces but that leads to ambiguity at the time of call. Any insights?
[EDIT]
I used namespaces as using namespace myNSpace
But when i used it as use myNSpace::random it worked fine.


回答1:


Why does your using namespace... not work, while your using ... works? First i want to show you another way to solve it by use of an elaborated type specifier:

int main() {
  // ...
  static class random r2; // notice "class" here
  // ...
}

That works because "class some_class" is an elaborated type specifier, which will ignore any non-type declarations when looking up the name you specify, so the POSIX function at global scope, which has the same name, will not hide the class name. You tried two other ways to solve it: Using directives and using declarations:

  • Then, you tried to stick the type into a namespace, and tried using namespace foo; in main - why did it not work?

    namespace foo {
    class random
    {
     public:
     random(){ std::cout << "yay!! i am called \n" ;}
    };
    }
    
    int main() {
     using namespace foo; 
     static random r2; // ambiguity!
     return 0 ;
    }
    

    You might wonder why that is so, because you might have thought that the using directive declares the names of foo into the local scope of main - but that's not the case. It's not declaring any name, actually it's just a link to another namespace. It's making a name visible during unqualified name lookup in that case - but the name is made visible as a member of the namespace enclosing both the using-directive and the denoted namespace (foo). That enclosing namespace is the global namespace here.

    So what happens is that name lookup will find two declarations of that name - the global POSIX random declaration, and the class declaration within foo. The declarations were not made in the same scope (declarative region), and so the function name doesn't hide the class name as usual (see man stat for an example where it does), but the result is an ambiguity.

  • A using declaration however declares one name as a member of the declarative region that it appears in. So, when random is looked up starting from main, it will first find a name that refers to the declaration of random in foo, and this will effectively hide the global POSIX function. So the following works

    namespace foo {
    class random
    {
     public:
     random(){ std::cout << "yay!! i am called \n" ;}
    };
    }
    
    int main() {
     using foo::random; 
     static random r2; // works!
     return 0 ;
    }
    



回答2:


Use a namespace

namespace myNamespace
{

    class random
    {
    public:
        random(){ std::cout << "yay!! i am called \n" ;}
    };

}

myNamespace::random r1;



回答3:


You're running into the POSIX random() function.

How do you avoid collisions? Know your libraries. Or you can do as I did to diagnose this, say man random. There it was, random(3).

I don't know what your namespace problem is, but it sounds like a separate question.




回答4:


In the case of g++, use command line option -ansi. This removes the non-standard function random from stdlib.h.

By default, g++ compiles as -std=gnu++98, which is "The 1998 ISO C++ standard plus amendments plus GNU extensions". So your code has done nothing wrong in order to be portable. It's just that without -ansi, you aren't using a compliant compiler.

These BSD (and Posix) stdlib functions are among those GNU extensions. From the glibc documentation:

http://www.gnu.org/s/libc/manual/html_node/BSD-Random.html

"There is no advantage to using these functions with the GNU C library; we support them for BSD compatibility only."

In general, if you want to write code that's portable to non-compliant compilers, then you just have to memorise the peculiarities of every single compiler in the world. GCC and MSVC are good ones to start with. Even with -ansi, you can make gcc non-compliant with other command-line options, such as -O2. This happened with the -fdelete-null-pointer-checks fiasco that hit the linux kernel a while back). Same goes for platforms whose libraries "extend" C (and hence C++), like BSD and Posix.

The reason there's a C standard in the first place is supposed to be so that you don't have to worry about this stuff, and personally I think it's unfortunate that other standards mess with C standard headers. But I'd guess that the fact of those functions being in stdlib on BSD dates from before C89. If so, then presumably it avoided a breaking change on BSD and other unixes at the time.

Btw, I found out that random() was in stdlib.h with g++ -E, which is useful when you want to know what on earth the system headers are doing to your program. I assumed that searching the web for "random" would be pointless. But "stdlib random" worked quite well.




回答5:


It looks to me like a problem with your particular compiler. It doesn't give an error with the compilers I have handy.




回答6:


If you have name collision problems use a namespace:

namespace mydata{
 class random{things};
}

And then call it mydata::random;




回答7:


To avoid these issues, use namespaces.. wikipedia

namespace myNamespace
{
     class random
     {
         ....
     };
}



回答8:


In general you avoid ambiguity errors by resolving them explicitly. Without putting your duplicate symbol in another namespace this can't work (except for cases where elaborated type specifiers help as litb points out) as you have two symbols in the same namespace and can't refer to either of them explicitly.

When putting your symbol in a namespace, you can:

  • fully qualify the name: myNamespace::mySymbol(x);
  • explicitly resolve the ambiguity: using myNamespace::mySymbol;

Note that pulling all symbols from your namespace in via using myNamespace; doesn't help as this doesn't resolve the ambiguity.

For full qualification its common to use short-hand names:

namespace mns = myNamespace;
mns::mySymbol(x);



回答9:


Are you including cstdlib? I get the error you show when I include it, I don't if I don't.




回答10:


the g++ compiler which i m using correctly compiled and ran your program. I m using MinGw 5.1.6 for running g++ on windows..



来源:https://stackoverflow.com/questions/1847822/name-collision-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!