See code below
#include <iostream>
#include <string>
namespace stringhelper
{
std::string to_string(int n) { return "0"; } // ignore wrong implementation. simplified for example purpose
}
using stringhelper::to_string;
class TestClass
{
public:
std::string to_string() const { return "TestClass:" + to_string(m_value); }
private:
int m_value;
};
int main()
{
TestClass tc;
std::cout << tc.to_string();
}
If TestClass does not implement function to_string(), within TestClass, it is able to resolve to_string(m_value) to stringhelper::to_string(int). However, the moment TestClass implements function to_string(), the compiler is unable to resolve to_string(int) to stringhelper::to_string.
Rather, it insists/resolves the function to TestClass::to_string and gave an error that the function TestClass::to_string does not take in 1 arguments.
Why is this so?
Environment:
Visual Studio 2008 Professional Edition 9.0.21022.8 RTM
Configuration: Win32
Windows 8
This behavior is not limited to Visual Studio 2008. If tested in modern Clang implementations you will see the same behaviour. As you may know, functions in derived classes which don't override functions in base classes but which have the same name will hide other functions of the same name in the base class.
The "problem" here is that you, by using the using statement introduces a function named to_string into a scope that is essentially a victim of the exact same thing as what happens in the above example, when looking at it from inside your class.
If the standard had you call member functions with this->foo() this would probably not have been an issue. But since function calls within a class are presumed to be part of the class and only if not found looked for in other scopes this becomes an issue.
Since you have an implementation in your class, that has priority and will be used. Since you want a version that takes an int as an argument, an overloaded version of your member function will be looked for and since it does not exist you get the error you see.
This is part of why using namespace can often introduce errors that might be unintuitive to understand. If you want to make sure you use the stringhelper::to_string implementation while you are in a class with a function that has the same name you have to be explicit.
This would work fine for instance, even if you keep your using statement.
#include <iostream>
#include <string>
namespace stringhelper
{
std::string to_string(int n) { return "0"; } // ignore wrong implementation. simplified for example purpose
}
using stringhelper::to_string;
class TestClass
{
public:
std::string to_string() const { return "TestClass:" + stringhelper::to_string(m_value); }
private:
int m_value;
};
int main()
{
TestClass tc;
std::cout << tc.to_string();
}
Related
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
A project I'm working on requires multiple targets to be compiled for. Per target the underlying implementation may vary as the device requires hardware to be configured differently.
In order to force target implementations to follow a interface/design contract system was designed. If a target does not implement said interface accordingly, an error will be thrown upon usage.
The following code is tested using gcc, arm-none-eabi-gcc and clang
namespace A {
namespace C {
void foo() {}
}
}
namespace B {
using namespace A::C;
void foo() {}
}
using namespace A;
namespace C {
}
int main() {
B::foo(); // ok
C::foo(); // won't compile
return 0;
}
Now there are multiple questions that arise when reasoning why this code would compile or not:
Why does the compiler not report unresolved ambiguity between A::foo(bool) and B::set(bool)?
Why does C::foo() not compile, since my theory is that the same naming structure is achieved but on a different manner:
Why does the compiler not report unresolved ambiguity between target::set(bool) and interface_contracts::set(bool)?
In the first code snippet, name hwstl::target::pin::set hides name hwstl::interface_contracts::pin::set.
For the call hwstl::device::pin::set(true);, name lookup stops upon finding hwstl::target::pin::set. Only one candidate function, no ambiguity.
For the call hwstl::unsatisfied_device::pin::set(true);, there is only one function called set which can be found anyway.
10.3.4.1 A using-directive does not add any members to the declarative region in which it appears.
Why does the following code not compile?
In the second code snippet, you call set by qualified id: hwstl::unsatisfied_device::pin::set, compiler will only try to find name inside namespace hwstl::unsatisfied_device::pin. Thus it failed in finding the name introduced by the using directive using namespace interface_contracts; outside it.
Here is a simplified version of your code:
namespace A {
void foo() {}
}
namespace B {
using namespace A;
void foo() {}
}
using namespace A;
namespace C {
}
int main() {
B::foo(); // ok
C::foo(); // won't compile
return 0;
}
The following code compiles fine and runs as expected:
#include <iostream>
namespace
{
struct Base
{
void print() const { std::cout << "test"; };
};
};
class Derived : public Base
{
};
int main()
{
Derived d;
d.print();
return 0;
}
But when looking at d during runtime using QuickWatch, IntelliSense seems to be unable to find
Base.
I solved this by putting Base in a named namespace instead of an unnamed.
So is it a bug in Visual Studio, or am I missing something out?
This problem with anonymous namepaces has been an issue in VC++ for a while - see http://msdn.microsoft.com/en-us/library/0888kc6a%28VS.80%29.aspx. From the linked doc:
The native C++ expression evaluator does not support anonymous namespaces.
and
The only way to watch the symbol test in this example is to use the decorated name:
e.g. (int*)?test#?A0xccd06570#mars##3HA (using the namespace hierarchy given in the example to illustrate the point). Just use the decorated name? That's so convenient! Thanks, Microsoft.
I have a class Room and it holds a vector of shared_ptrs to Option objects like so:
private:
vector<shared_ptr<Option> > options;
But for some reason when I build, I get the following errors:
'shared_ptr' : unspecialized class template can't be used as a template argument for template parameter '_Ty', expected a real type
'std::tr1::shared_ptr' : use of class template requires template argument list
Strangely, I also have a vector of shared_ptrs, exact same syntax but there's no problem with that one.
There's also a bunch of places that bring up the error "'Option': undeclared identifier", which brings me to think it might be a problem with the Option class, but it seems to be fine. Here's the code for Option:
Option.h:
#pragma once
#include "Room.h"
#include <memory>
using namespace std;
class Option
{
protected:
int id;
char* text;
public:
Option(void);
Option(int, char*);
virtual ~Option(void);
char* getText();
int getID();
};
Option.cpp:
#include "Option.h"
#include "Room.h"
#include <memory>
using namespace std;
Option::Option(void)
{
}
Option::Option(int newID, char* newText){
id = newID;
text = newText;
}
Option::~Option(void)
{
}
char* Option::getText(){
return text;
}
int Option::getID(){
return id;
}
There is a bit of conjecture in this answer since you haven't posted the code for the Room class. I'm assuming this code
private:
vector<shared_ptr<Option> > options;
is in Room.h. Your Option.h file includes Room.h, hence the Room class gets declared before the Option class. So Option is an incomplete type when the Room class' destructor is compiled and the shared_ptr implementation tries to delete the Option object.
From the code above, I don't see why Option.h needs to include Room.h, in fact, it should be the other way around. If it does indeed need to include the file, you should be able to work around the problem by explicitly declaring Room::~Room() out-of-line in Room.cpp.
EDIT:
Turns out ~shared_ptr<T> does not require T to be a complete type. However, shared_ptr<T>( T* ) and shared_ptr<T>::reset( T* ) do, and the problem may be because some operation on the vector is invoking a call to one of these (more likely the former).
vector<shared_ptr<Option >>
You almost did that right :)
vector<shared_ptr<Option> >
It's the two > characters that, when touching, cause the strange errors you see. It is being interpreted as the >> operator.
BTW, thank you for posting your code exactly as it is rather than typing it back in and possibly hiding the mistake.
I'm working in Visual Studio 2008 on a C++ programming assignment. We were supplied with files that define the following namespace hierarchy (the names are just for the sake of this post, I know "namespace XYZ-NAMESPACE" is redundant):
(MAIN-NAMESPACE){
a bunch of functions/classes I need to implement...
(EXCEPTIONS-NAMESPACE){
a bunch of exceptions
}
(POINTER-COLLECTIONS-NAMESPACE){
Set and LinkedList classes, plus iterators
}
}
The MAIN-NAMESPACE contents are split between a bunch of files, and for some reason which I don't understand the operator<< for both Set and LinkedList is entirely outside of the MAIN-NAMESPACE (but within Set and LinkedList's header file).
Here's the Set version:
template<typename T>
std::ostream& operator<<(std::ostream& os,
const MAIN-NAMESPACE::POINTER-COLLECTIONS-NAMESPACE::Set<T>& set)
Now here's the problem: I have the following data structure:
Set A
Set B
Set C
double num
It's defined to be in a class within MAIN-NAMESPACE. When I create an instance of the class, and try to print one of the sets, it tells me that:
error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'const MAIN-NAMESPACE::POINTER-COLLECTIONS-NAMESPACE::Set' (or there is no acceptable conversion)
However, if I just write a main() function, and create Set A, fill it up, and use the operator- it works.
Any idea what is the problem? (note: I tried any combination of using and include I could think of).
Strange - even though putting free functions associated with a type to a different namespace is a bad practice, the global namespace declarations are always visible.
The only thing I can think of is that declaration with the same name in MAIN-NAMESPACE would shadow the one in the global namespace - isn't there an operator<<, possibly for totally unrelated type, in MAIN-NAMESPACE? If so, you should fix that by using ::operator<< declaration in MAIN-NAMESPACE. Example:
namespace A
{
namespace B
{
class C{};
}
}
void f(A::B::C*);
namespace A
{
void f(int*); // try commenting
using ::f; // these two lines
void g()
{
B::C* c;
f(c);
}
}
OK I figured this out.
jpalecek's intuition about there existing another operator<< in the namespace was correct (apparently I forgot to comment it out).
The lookup rules for namespaces first start the search in the function call's namespace and search up the enclosing namespaces, right up to the global namespace (then it does the Argument dependent lookup if no match is found). However, if along the way it finds some match for operator<<, it stops the search, regardless of the fact that the types used in those functions may be incompatible, as was the case here.
The solution is either to include it into the MAIN-NAMESPACE (which I'm not allowed to), or import it from the global namespace with "using ::operator<<".
Try calling the function explicitly?
::operator<<( cout, myObj );
As SoaBox pointed out, try calling it explicitly.
For your information, if you wish to call a global function which has been hidden in the current namespace precede the function with :: to bypass the local function and call the global function.
Try calling the function explicitly?
::operator<<( cout, myObj );
Yes, that does work!
it will try to find the f function in
the current namespace (at the place of
call) or in the enclosing namespaces
of c1 and c2 types (namespace1,
namespace2::namespace3), but it will
not try other namespaces in the
search.
So let's see if I got this right: the reason invoking the operator<< from a main() function worked is because I was in the global namespace (as was operator<<).
The reason it failed when invoking from the class I implemented is because the class was in a not global namespace and there were no variables in it that pointed the compiler towards the global namespace.
OK people asked for a specific examples, so here's the relevant part of the code.
//Disclamer: in the slim case someone from my uni sees this, encounters it in the submission file, and decides I copied it or something, my student number is 311670137
This is the header file Set.h:
namespace MTM {//This is the MAIN-NAMESPACE
namespace PointerCollections {
(ITERATORS AND PREDICATE CLASSES)
template<typename T>
class Set {
public:
/////////////////////////////////
// Definitions
/////////////////////////////////
private:
/////////////////////////////////
// Definitions
/////////////////////////////////
};
///////////////////////////////////////////////////////////////////////////////
// The implementation part.
///////////////////////////////////////////////////////////////////////////////
}
}
// operator<< - the same a Set::print(std::ostream& os,
// const BinaryPredicate<T>& predicate)
// function called with the 'predicate' parameter omitted
template<typename T>
std::ostream& operator<<(std::ostream& os,
const MTM::PointerCollections::Set<T>& set){
set.print(os);
return os;
}
This is what I defined in a different file:
namespace MTM {
using std::ostream;
class Schedule {
public:
///////////////////
//Definitions, including:
///////////////////
void registerStation(string stationName);
void reportRegisteredStations(std::ostream& outputStream) const;
private: //My database
//All the classes Set recieves are defined elsewhere
Set<RegisteredStation> places;
Set<BusLine> busses;
Set<TrainLine> trains;
double tarifForBuses;
double tarifForTrains;
};
}
And here's from the main:
Schedule s();
s.registerStation("1");
s.reportRegisteredStations(cout);//This invokes the error. Definition follows:
reportRegisteredStations is defined as:
void Schedule::reportRegisteredStations(std::ostream& outputStream) const{
outputStream<<places;
}
This works for me
#include <iostream>
#include <string>
using std::string;
namespace MTM {//This is the MAIN-NAMESPACE
namespace PointerCollections {
template<typename T>
class Set {
};
}
}
template<typename T>
std::ostream& operator<<(std::ostream& os,
const MTM::PointerCollections::Set<T>& set){
return os;
}
namespace MTM {
using std::ostream;
using PointerCollections::Set;
class Schedule {
public:
///////////////////
//Definitions, including:
///////////////////
void registerStation(string stationName);
void reportRegisteredStations(std::ostream& outputStream) const;
private: //My database
//All the classes Set recieves are defined elsewhere
Set<int> places;
Set<int> busses;
Set<int> trains;
double tarifForBuses;
double tarifForTrains;
};
void Schedule::reportRegisteredStations(std::ostream& outputStream) const{
outputStream<<places;
}
}
int main()
{
MTM::Schedule s;
s.reportRegisteredStations(std::cout);
}
CORRECTION: The text below is based on experience with the g++ family of compilers. After the comment to the answer I have reread the standard (which states that ADL will be used over regular name lookup, and regular name lookup should find the operator<<). I have also tried with comeau compiler (the most standard compliant compiler I know of) and the symbol is found. It seems as a problem with g++ (tried versions 3.3, 4.1, 4.3).
Original answer:
Search for Koening lookup (technically ADL: Argument dependent lookup).
The short answer is that if you have the following class:
namespace test {
class A {};
}
the stream insertion operator should be defined as:
namespace test {
std::ostream& operator<<( std::ostream&, A const & );
}
Functions or operators should be defined in the same namespace as one of the arguments that it takes. (*)
When the compiler finds a function call such as:
namespace test2 {
void g() {
namespace1::class1 c1;
namespace2::namespace3::class2 c2;
f( c1, c2 );
}
}
it will try to find the f function in the current namespace (at the place of call) or in the enclosing namespaces of c1 and c2 types (namespace1, namespace2::namespace3), but it will not try other namespaces in the search.
(*) In this case, you are pretty much limited to the test namespace, as you are not allowed to add a function to the std namespace (only template specializations).
End of original post.
Even if as commented before this may just be a problem with the compiler, it is common usage and recommended to define all free functions that operate on a user defined type in the same namespace as the type itself.