Namespaces & Source Files#
Consider the following code:
// current_thread.h
#ifndef _CURRENT_THREAD_H_
#define _CURRENT_THREAD_H_
namespace mymuduolib {
namespace currentthread {
extern __thread int t_cached_tid;
void cachedTid();
} // namespace currentthread
} // namespace mymuduolib
#endif // _CURRENT_THREAD_H_
To implement the definitions in the source file, you can add the mymuduolib::currentthread::
prefix before the implementation names to specify the namespace:
// current_thread.cpp
#include "current_thread.h"
#include <unistd.h>
#include <sys/syscall.h>
__thread int mymuduolib::currentthread::t_cached_tid = 0;
void mymuduo::currentthread::cachedTid() {
if (t_cached_tid == 0) {
// get the current id through Linux system call
t_cached_tid = static_cast<pid_t>(::syscall(SYS_gettid));
}
}
If the namespace prefix is not added, there will be two t_cached_tid
and cachedTid()
definitions, one in the mymuduo::currentthread::
namespace and another in the ::
namespace. The definition in the mymuduo::currentthread::
namespace is not implemented. If using namespace mymuduolib::currentthread;
is used in a module, it will call the cachedTid()
function in the mymuduolib::currentthread::
namespace. (Of course, this code will not compile without adding the namespace prefix because the variable t_cached_tid
in the function will have an ambiguous specification).
Alternatively, you can place the implementation code in the same namespace as the header file:
// current_thread.cpp
#include "current_thread.h"
#include <unistd.h>
#include <sys/syscall.h>
namespace mymuduolib {
namespace currentthread {
__thread int t_cached_tid = 0;
void cachedTid() {
if (t_cached_tid == 0) {
// get the current id through Linux system call
t_cached_tid = static_cast<pid_t>(::syscall(SYS_gettid));
}
}
} // namespace mymuduolib
} // namespace currentthread
However, in this case, you cannot simply use using namespace mymuduolib::currentthread;
because the scope of the function and variable implementations needs to be explicitly specified. If not specified, it means that the subsequent implementation content is independent of that namespace.
But for member implementations in a class, you can use the using namespace
namespace:
// poller.h
#ifndef _POLLER_H_
#define _POLLER_H_
namespace mymuduolib {
namespace net {
class Poller {
Poller();
};
}
} // namespace net
#endif // _POLLER_H_
In the source file:
// poller.cpp
#include "poller.h"
// mymuduolib::net::Poller::Poller() {}
using namespace mymuduolib::net;
Poller::Poller() {}
Namespaces & Forward Declarations#
Forward declarations can avoid circular dependency issues, but there is a common pitfall when encountering namespaces with forward declarations.
Consider the following erroneous code:
// addr.h
#ifndef _ADDR_H_
#define _ADDR_H_
namespace net {
class Addr {};
} // namespace net
#endif // _ADDR_H_
// http_connect.h
#ifndef _HTTP_CONNECT_H_
#define _HTTP_CONNECT_H_
class Addr;
namespace net {
class HttpConnect {
public:
HttpConnect(const Addr &);
};
} // namespace net
#endif // _HTTP_CONNECT_H_
// http_connect.cpp
#include "http_connect.h"
#include "addr.h"
using namespace net;
HttpConnect::HttpConnect(const Addr &) {}
// main.cpp
#include "http_connect.h"
int main() {
net::HttpConnect(Addr());
}
Error message:
http_connect.cpp:6:1: error: no declaration matches ‘net::HttpConnect::HttpConnect(const net::Addr&)’
6 | HttpConnect::HttpConnect(const Addr &) {}
| ^~~~~~~~~~~
In file included from http_connect.cpp:1:
http_connect.h:8:7: note: candidate is: ‘constexpr net::HttpConnect::HttpConnect(net::HttpConnect&&)’
8 | class HttpConnect {
| ^~~~~~~~~~~
http_connect.h:8:7: note: ‘constexpr net::HttpConnect::HttpConnect(const net::HttpConnect&)’
http_connect.h:10:5: note: ‘net::HttpConnect::HttpConnect(const Addr&)’
10 | HttpConnect(const Addr &);
| ^~~~~~~~~~~
http_connect.h:8:7: note: ‘class net::HttpConnect’ defined here
8 | class HttpConnect {
| ^~~~~~~~~~~
You might think that this error is caused by the using namespace
, but it is not. Even using net::HttpConnect::HttpConnect(const net::Addr&)
will result in the same error.
The issue here is actually with the forward declaration. We need to place the forward declaration class Addr
inside the namespace net
because the forward declaration class Addr
does not exist in the ::
scope.
// http_connect.h
#ifndef _HTTP_CONNECT_H_
#define _HTTP_CONNECT_H_
namespace net {
class Addr;
class HttpConnect {
public:
HttpConnect(const Addr &);
};
} // namespace net
#endif // _HTTP_CONNECT_H_
If there are any mistakes, please let me know.