Ambiguous symbol - c++

I have declared a class Integer in a custom namespace:
namespace MyNameSpace
{
class Integer {};
}
And I am using it in a method like this:
void someMethod()
{
using namespace MyNameSpace;
SomeClass x(Integer("some text", 4));
}
This gives
10> error C2872: 'Integer' : ambiguous symbol
10> could be 'g:\lib\boost\boost_1_47_0\boost/concept_check.hpp(66) : boost::Integer'
10> or '[my file] : MyNameSpace::Integer'
I have searched my code base for "namespace boost" and "using boost" with fulltext search but didn't find a line like "using namespace boost;". This is supported by the test that
void someMethod()
{
shared_ptr<int> x;
using namespace MyNameSpace;
//SomeClass x(Integer("some text", 4));
}
gives
error C2065: 'shared_ptr' : undeclared identifier
whereas
void someMethod()
{
boost::shared_ptr<int> x;
using namespace MyNameSpace;
//SomeClass x(Integer("some text", 4));
}
compiles.
Is there any other reason why the "ambiguous symbol" error can occur??

Compiler just prevents you from mixing this classes up. Even when you are not using namespace "boost".

Namespaces are essentially "last names" or "family names" for the stuff in them. In your case Integer()'s whole name is MyNameSpace::Integer(). You specific errors are a splendid example of the first rule of using namespaces. DO NOT USE "USING" STATEMENTS! If you leave them out completely, yes, you have to type a few extra things to placate the compiler. But you never have collisions or to ask anything like "does boost have an Integer somewhere".
Secondly, someMethod() is outside any class and outside any namespace. It really ought to look more like MyNameSpace::Integer::someMethod() or more reasonably be inside a
namespace MyNameSpace
{
Integer::someMethod(
}
Once you do this, the compiler WILL help you find where stuff is or isn't.
Good luck!

Related

Resolve std::string to something else than ::std::string - is it possible?

This is a follow-up question from: constructing string from NULL?
The following:
void test(const std::string& s);
int main(){
test(NULL);
}
Fails when run, but is legal c++.
In order to try to catch some of those cases, as an alternative ive considering if std::string can be replaced in the following way:
#include <string>
namespace {
namespace std {
struct string : public ::std::string { //so far everything is good
};
}
}
int main ()
{
std::string hello;//failure: ambiguous symbol
return 0;
}
Gives the following error:
<source>(17): error C2872: 'std': ambiguous symbol
C:/data/msvc/14.22.27905/include\string(19): note: could be 'std'
<source>(7): note: or '`anonymous-namespace'::std'
<source>(17): error C2872: 'std': ambiguous symbol
C:/data/msvc/14.22.27905/include\string(19): note: could be 'std'
<source>(7): note: or '`anonymous-namespace'::std'
Compiler returned: 2
I guess it is not possible to make it resolve without writing a more (fully) qualified name ? but is it possible to write std::string in the global namespace and have it resolve to something else while ::std::string is a valid type.
Background: after some failed attempts with cppcheck and cpp core check im trying to find all cases of std::string str = 0 or NULL or nullptr - since those will fail at runtime. And I thought this might be a way forward.
I ended up modifying the basic_string template ala. basic_string(int) = delete;
basic_string(::std::nullptr_t) = delete; - this won't catch all cases but does indeed seem to catch the direct cases at least
Resolve std::string to something else than ::std::string - is it possible?
[...]
...as an alternative ive considering if std::string can be replaced in the following way...
As far as I know, it is not possible outside of your anonymous namespace scope because you have no way to resolve the ambiguity (not to my knowledge).
As you can see below, since you are inside the scope of the anonymous namespace, it will be fine:
#include <string>
namespace
{
namespace std
{
struct string : public ::std::string
{
};
}
std::string hello; // Fine
}
int main()
{
std::string hello2; // Cannot be something else that ambiguous
return 0;
}
But even worse, the problem is not about std::string itself but about the std namespace.
Indeed, outside of the scope of your anonymous namespace, every call of std becomes ambiguous too.This is the error pointed by the compiler. There are two std namespaces accessible as is from the global scope.
So the following example becomes broken:
#include <string>
#include <vector>
namespace
{
namespace std
{
struct string : public ::std::string
{
};
}
std::string hello; // Fine
}
int main()
{
std::vector<int> a; // FAIL: reference to 'std' is ambiguous
return 0;
}
To fix this ambiguity over accessing the original std namespace, you'll need to write it as follows:
::std::vector<int> a; // Fully qualified name: Only way to refer to the `::std` namespace
As you can see, it still does not solve the issue and even worse, it adds a huge inconvenience.
Therefore the morality is:
Do not hide an already existing type but create a distinct one instead.
In the same way, do not hide a namespace (by defining the same namespace into an anonymous one --> evil).
(I'm open to any improvement proposal of this answer)
Could you use this kind of solution : Rather than working on std::string, you work on the function that will cause the problem
#include <string>
void test(const std::string& s){
}
// add a new function which use a pointer :
void test (const char* _Nonnull s) {
test(std::string(s));
}
int main()
{
test(NULL);
return 0;
}
Then clang will generate a warning :
1 warning generated.
ASM generation compiler returned: 0
<source>:13:14: warning: null passed to a callee that requires a non-null argument [-Wnonnull]
test(NULL);
see https://godbolt.org/z/PujFor

Defining a function in a namespace other than the ADL, "local" or global namespace

See the code below:
#include <iostream>
/// Definition of void perform(a_lib::a_class&). Where should I put this definition?
/// See the comments below for where I've tried placing it.
// void perform(a_lib::a_class&) {
// std::cout << "performing on a_lib::a_class" << std::endl;
// }
namespace a_lib {
class a_class { };
// WORKS HERE but it pollutes a_lib (namespace of third-party library).
}
namespace mine {
// DOESN'T WORK HERE: "use of undeclared identifier 'perform'".
}
// WORKS HERE but it pollutes the global namespace.
namespace b_lib {
// WORKS HERE but it pollutes b_lib (namespace of third-party library).
template <typename Type>
void b_func(Type& obj) {
perform(obj);
}
}
namespace mine {
// DOESN'T WORK HERE: "use of undeclared identifier 'perform'".
void run() {
a_lib::a_class a_obj;
b_lib::b_func(a_obj);
}
}
int main(int, char**) {
mine::run();
return 0;
}
a_lib and b_lib are namespaces belonging to two different third-party libraries. mine is my own namespace.
I've been taught that it's a bad idea to pollute the global namespace and in this question they also say that adding types to std is a bad idea. I'm thinking the latter is true for namespaces in general; you should not add types to a namespace that's not yours.
But how I would I solve the problem above without breaking these principles? Where should I put the definition of perform() and how can I get b_func() to call it?
Context: I'm trying to add an external cereal serialize() for a SFML type in my own namespace. This here is a reduced example.
You need to identify where the compiler, when processing "b_func" can find the "perform".
namespace mine {
// DOESN'T WORK HERE: "use of undeclared identifier 'perform'".
// dom - yes it will, but there is 'more' to the name than your example shows
void perform(Type& obj) { /* do something with obj */}
}
// WORKS HERE but it pollutes the global namespace.
namespace b_lib {
// WORKS HERE but it pollutes b_lib (namespace of third-party library).
// dom - use here is easy with correct and 'more-complete' name:
template <typename Type>
void b_func(Type& obj) { mine::perform(obj); }
// -----------------------^^^^^^^^^^^^^^^^^^^ --- more to name
}
Since "mine" is a namespace, a more complete name can 'reach across' the name spaces.
Note that at mine::perform() implementation, "Type" must also be defined to use the obj.

Namespace name in c++

I am trying to create a namespace in c++ in the following way:
namespace MyCompany.Library.Myproduct {
public ref class ClassWrapper
{
};
}
I am getting error:
Error 1 error C2059: syntax error : '.' ClassWrapper.h 7 1 MyCompany.Library.Myproduct
Why can not I have . in namespace?
Edit1
This namespace definition is in a c++/cli and would be used in c# code. in C# this namespace is valid, but it seems it is not valid in c++. How can define c# compatible namespaces in c++/cli code?
You're not allowed to use the dot in namespace name. However, you can have nested namespaces.
namespace Boap
{
namespace Lib
{
namespace Prod
{
class Llama
{
public:
Llama()
{
std::cout << "hi" << std::endl;
}
};
}
}
};
And instanciate your llama this way:
Boap::Lib::Prod::Llama l;
AFAIK namespace and classname follow the same namming rules than variables.
A variable's name cannot start with a numeric character, and the same apply to class / namespace's names. The same goes for ".".
EDIT: The following is pure assumptions, because I have no knowledge of C# or windows CLI.
Does it make sense that a nested namespace in C++ (eg Boap::Lib) would be translated into Boap.Lib in C#? Maybe it's just as simple as that.
Now, in 2023 it is possible to achieve what you want; with ::. You need to make sure the C++ Language Standard is set to at least C++17.
Then this code would compile and work:
namespace MyCompany::Library::Myproduct {
public class ClassWrapper
{
};
}

Namespace's don't make sense to me

Suppose I have the following defined in a header file:
namespace MyNamespace
{
Class global_c;
}
Then I do this in a source file:
namespace MyNamespace
{
void MyClass::Function( )
{
::global_c.DoSomething( );
}
}
global_c turns out as undefined by the compiler, if I do just global_c.DoSomething( ); however it compiles fine, if I add 'using namespace MyNamespace;' to the top of the file it also works fine.
Since global_c lives in the same namespace as 'MyClass' why can't it be resolved just because '::' is added to the front of it?
Because you are explicitly telling the compiler to use the global namespace by prepending the variable with ::. As global_c does not exist in the global namespace it throws an error.
The compiler is just doing what you told it to do. Think of :: as Global::.

Multiple namespace declaration in C++

Is it legal to replace something like this:
namespace foo {
namespace bar {
baz();
}
}
with something like this:
namespace foo::bar {
baz();
}
?
You can combine namespaces into one name and use the new name (i.e. Foobar).
namespace Foo { namespace Bar {
void some_func() {
printf("Hello World.");
}
}}
namespace Foobar = Foo::Bar;
int main()
{
Foobar::some_func();
}
Pre C++17:
No, it's not. Instead of a bunch of indented nested namespaces, it's certainly valid to put them on the same line:
namespace Foo { namespace Bar { namespace YetAnother {
// do something fancy
} } } // end Foo::Bar::YetAnother namespace
C++17 Update:
You can now nest namespaces more cleanly in C++17:
namespace Foo::Bar::YetAnother {
// do something even fancier!
}
For anyone wondering, the form namespace foo::bar is supported since C++17. References:
http://en.cppreference.com/w/cpp/language/namespace
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4230.html
Qualified names, like something::someting_else in C++ can only be used to refer to entities that have already been declared before. You cannot use such names to introduce something previously unknown. Even if the nested namespace was already declared before, extending that namespace is also considered as "introducing something new", so the qualified name is not allowed.
You can use such names for defining functions previously declared in the namespace
namespace foo {
namespace bar {
int baz();
}
}
// Define
int foo::bar::baz() {
/* ... */
}
but not declaring new namespaces of extending existing ones.
No; it's a syntax error.
Did you try it? Visual C++ gives me the following errors:
1>C:\...\foo.cpp(31): error C2061: syntax error : identifier 'bar'
1>C:\...\fooo.cpp(31): error C2143: syntax error : missing ';' before '{'
As per the grammar in $2.10, an identifier cannot have the token ":". So the name foo::bar is ill-formed.