Is it possible to import a function to the namespace, but not export it?

Viewed 638

Is it possible to import a function (or other symbol) to a namespace but not export it? For example, I want to import std::string into the current namespace, but I don't want current::string to be visible.

namespace current {
  using std::string;
  string func();
}

current::string should not be a thing.

The use case is simply to cut down on typing (and constantly forgetting to std::string among others) and make the code a little more legible without all the namespace syntax cluttering the code.

3 Answers

Is it possible to import a function (or other symbol) to a namespace but not export it?

No.

A using directive will introduce all the symbols that refer to the name you use in the declaration and they will be visible to the users of current as if they were actually declared in the namespace itself.

The relevant part of the standard is in [namespace.udir]/1:

A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. During unqualified name lookup (6.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace. [ Note: In this context, “contains” means “contains directly or indirectly”. — end note ]

"All problems in computer science can be solved by another level of indirection" – David Wheeler

In this case, it is definitely so:

namespace current {
    namespace impl {
        using std::string;
        string func();
    }

    using impl::func;
}

Admittedly, there are costs:

  • It forces you to list every single type or function that you want to export from current, given that in C++ there is no way to exclude individual symbols from e.g. a using namespace. (Just regard that as a feature as it makes the contents of your API deliberate instead of coincidental.)
  • This will not work if you need to remain ABI compatible (the mangled name of func will change on all implementations I know of)

BTW, the namespace name current suggests that you might also have versioning in mind. The two approaches can be combined nicely, e.g.:

namespace _v1 {
    namespace impl {
        int func();
    }

    // Exports
    using impl::func;
}
namespace _v2 {
    namespace impl {
        using std::string;
        string func();
    }

    // Exports
    using impl::func;
}

namespace current = _v2;

No, and your code is bad practice. While your particular example of std::string may not cause conflicts, unnamed lookup can pull references to other string's defined outside the scope of the namespace, leading to possibly redeclaration errors or unnamed lookup using a different name than you intended. This can happen for example: a) you or someone else in your code uses a name that conflicts with a library (like distance), b) a library uses a name that conflicts (like Boost), c) or different translation units pull in different names from outside scopes, causing similar code to have entirely different behavior.

Either fully qualify your declarations always or at least use using ::std::string.

Related