Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any portable tricks to obtain namespace name in C++?

Tags:

c++

namespaces

I have some well-formed code looks like this:

NAMESPACE_BEGIN(Foo)
inline void test() {
    string s = xxx;
}
NAMESPACE_END(Foo)

So, is there any portable tricks by using the NAMESPACE_BEGIN() macro to obtain namespace name "Foo" in test()?

I'm thinking of something like this, but it would surely cause symbol redefinition:

#define NAMESPACE_BEGIN(x) \
    namespace x { \
        inline const char *_curNamespace() { \
            return #x; \
        }
#define NAMESPACE_END(x) \
    }

There's also a workaround looks like this, but that's not very convenient

#define NAMESPACE_NAME Foo
// using a header file so that we can use #ifdef guard
#include "MyNamespaceBegin.h"
...
#include "MyNamespaceEnd.h"

EDIT:

  • Why I need this:

    I'm using much of macro to generate codes to achieve some dynamic reflection logic (yes, not static template reflection), it's all right within class scope by using static member function, but does not work for namespaces

  • Why not to manually declare the name getter once:

    What I want is something like this:

    // the global default version
    const char *_curNamespace() {return "";}
    
    namespace X {
        // the local namespace version
        const char *_curNamespace() {return "X";}
    
        // some verbose reflection register code
        ...
        registerSomething(_curNamespace());
        ...
    }
    

    Of course, all of the verbose register code should be generated by macro

    And, app level user should not care about the _curNamespace(), so, I want to simplify the user's usage, by using a custom NAMESPACE_BEGIN(xxx) macro at any case

  • If you are still curious about what I'm doing, check this: https://github.com/ZFFramework/ZFFramework

    I'm using lots of tricks to achieve fully dynamic reflection in pure C++, to achieve some of my fancy thoughts, for now, this project is just for fun, I have no idea whether it has practicability

EDIT2:

For now, I think the best workaround should be like this:

#define NAMESPACE_BEGIN(ns) \
    namespace ns { \
        extern const char *__curNS();
#define NAMESPACE_END(ns) \
    }
#define NAMESPACE_REG(ns) \
        const char *__curNS() {return #ns;}
  • app level users still only need to care about NAMESPACE_BEGIN
  • NAMESPACE_REG must be declared exactly once, in source file
    • if not, undefined symbol would happen
    • if more than once, duplicated symbol would happen
    • although it's annoying and sometimes you need additional source file to hold the NAMESPACE_REG, the strict rule should prevent user from forgetting the ugly workaround
like image 783
ZSaberLv0 Avatar asked Jul 05 '18 06:07

ZSaberLv0


People also ask

Can you use namespaces in C?

No, C does not have a namespace mechanism whereby you can provide “module-like data hiding”.

What is namespace explain with example?

A file path, which uses syntax defined by the operating system, is considered a namespace. For example, C:\Program Files\Internet Explorer is the namespace that describes where Internet Explorer files on a Windows computer.

Can a namespace have the same name as a class?

Inside a namespace, no two classes can have the same name.

Can we create our own namespace in C++?

C++ allows us to define our own namespaces via the namespace keyword. Namespaces that you create for your own declarations are called user-defined namespaces. Namespaces provided by C++ (such as the global namespace ) or by libraries (such as namespace std ) are not considered user-defined namespaces.


2 Answers

You are making much fuss over something that is trivial to implement.

First of all, use of NAMESPACE_BEGIN and NAMESPACE_END seems unnecessary to me. I don't see how that is more readable or useful than

namespace Foo
{
}

If getting the name of the namespace is important/useful, add a trivial function.

namespace Foo
{
   inline std::string get_name() { return "Foo"; }
}

Small sized real world applications need thousands of lines of code. Large sized real world applications need millions of lines of code. From that perspective, implementing a one line inline function is a very minor task.

like image 62
R Sahu Avatar answered Nov 13 '22 09:11

R Sahu


This solution employs a bit of preprocessor magic and has these features:

  • Namespace is mentioned only once
  • Access to a macro containing the unquoted name
  • Access to a macro containing the quoted name
  • Support for repeating the same namespace
  • Support for different namespaces
  • Misuse of the BEGIN/END macros is detected
  • Cleanup, i.e. no extra macros defined outside the BEGIN/END block

It does not support nested namespaces.

Example of usage:

#include "framework.hpp"

#define NAMESPACE_NAME Foo
#include NAMESPACE_BEGIN
    // Here you have access to NAMESPACE_NAME (unquoted, i.e. Foo)
    // and also to NAMESPACE_NAME_STRING (quoted, i.e. "Foo")
#include NAMESPACE_END


// NAMESPACE_NAME and NAMESPACE_NAME_STRING do not exist
// outside the block, so they cannot be misused


// Different namespaces in the same TU are supported
#define NAMESPACE_NAME Bar
#include NAMESPACE_BEGIN
    inline std::string f()
    {
        return NAMESPACE_NAME_STRING;
    }
#include NAMESPACE_END


// Repeating the same namespace is also supported
#define NAMESPACE_NAME Foo
#include NAMESPACE_BEGIN
    inline std::string f()
    {
        return NAMESPACE_NAME_STRING;
    }
#include NAMESPACE_END

The implementation follows:

framework.hpp

#pragma once

#define NAMESPACE_BEGIN "framework_namespace_begin.hpp"
#define NAMESPACE_END "framework_namespace_end.hpp"

framework_namespace_begin.hpp

#ifndef NAMESPACE_NAME
#error "NAMESPACE_NAME not defined"
#endif

#define NAMESPACE_IN_NAMESPACE 1

#define NAMESPACE_NAME_DO_STR(X) #X
#define NAMESPACE_NAME_STR(X) NAMESPACE_NAME_DO_STR(X)
#define NAMESPACE_NAME_STRING NAMESPACE_NAME_STR(NAMESPACE_NAME)

namespace NAMESPACE_NAME {

framework_namespace_end.hpp

#ifndef NAMESPACE_IN_NAMESPACE
#error "NAMESPACE_IN_NAMESPACE not defined"
#endif

}

#undef NAMESPACE_NAME
#undef NAMESPACE_NAME_STRING
#undef NAMESPACE_IN_NAMESPACE
like image 31
Acorn Avatar answered Nov 13 '22 10:11

Acorn