Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Curious namespace trick, looking for feedback on compatibility/potential problems?

70 views
Skip to first unread message

Dmitry Chichkov

unread,
Jan 21, 2016, 1:58:14 PM1/21/16
to
There is a trick with 'inline namespace' that seems to allow static function overriding in C/C++. Which in turn allows organizing cross-platform code in a nice way.

I'm trying to get feedback on potential pitfalls of that technique. Here is a Git wiki page that describes it: https://github.com/dchichkov/curious-namespace-trick/wiki/Curious-Namespace-Trick

Briefly, it goes along these lines - if the code below would be compiled with -Dplatform=arm, the C function dot() in the common code would call platform specific add(). If platform specific add() is not available, common one will be called. If the code is built with -Dplatform=common the common version of add() will be called.


// output:
// dmitry@t:~$ g++ func.cpp -Dplatform=common ; ./a.out
// common add
// dmitry@t:~$ g++ func.cpp -Dplatform=arm ; ./a.out
// arm add
#include <stdio.h>

namespace project {
// arm/math.h
namespace arm {
inline void add_() {printf("arm add\n");} // try comment out
}

// math.h
inline void add_() {
//
printf("common add\n");
//
} inline namespace platform {inline void add() {add_();}}


inline void dot_() {
//
add();
//
} inline namespace platform {inline void dot() {dot_();}}
}

int main() {
project::dot();
return 1;
}


This technique seems to be an alternative to weak linking, CRTP, traits, etc. and it works for functions, template functions and in C++-11 for template types. It be great to get some feed-back from C/C++ gurus on potential problems with this approach and better alternatives.


-- Dmitry Chichkov

Alf P. Steinbach

unread,
Jan 21, 2016, 2:39:38 PM1/21/16
to
Code that's specific to a given platform typically needs headers for
that platform. And these headers are typically not available when the
code is compiled on another platform. This means that some selection of
which code to compile is needed anyway, and I would think that then the
above technique becomes just an added complication, redundant.

As I understand it inline namespaces (I haven't used them) were designed
to support versioning for template code, where client code may need to
specialize templates in their apparent original namespaces.

Three main ways of selecting which code to compile:

• conditional code blocks via `#if` and family,

• selection of headers via the compiler's include path, and

• creating a platform (or whatever-) specific code bundle by a tool that
picks that platform's files.

In addition it's technically possible to select headers via macro-based
include directives, but I tried that once and it quickly became a real
mess, running up against compiler and compiler version differences and
non-standard functionality.

Anyway, instead of using a macro to redefine a word like lowercase
"platform" that can easily be used for other purposes somewhere, I'd use
more obviously macro macros, with ugly all uppercase names, to let the
compiler see just one “inline”. But then we're into selecting which code
to compile again. Which seems to make this redundant.


Cheers & hth.,

- Alf

Dmitry Chichkov

unread,
Jan 21, 2016, 6:24:39 PM1/21/16
to
Hi Alf,

Yes, it is still necessary to select the correct platform-specific headers. And the tool like cmake, omake, etc would be the standard way of doing it. The problem is, after you've included a platform-specific definition - for example arm/math.h, you have duplicate function/type/template definitions in the common code (for example math.h) and in the platform-specific code.

This can be solved, if you'd simply implement the whole set of function in every platform-specific file, redirecting every unimplemented call to common routine. But if the number of supported platforms is large, this adds a lot of code/maintenance. There are ways to address that with preprocessor or templates, but it either forces one to mangle function names or it supports C++ only and requires to template every function/type, etc. It seems like this inline namespace trick gives cleaner alternative, but I haven't seen it in practice, and I'm not sure what are the potential pitfalls...

Cheers,
Dmitry
> * conditional code blocks via `#if` and family,
>
> * selection of headers via the compiler's include path, and
>
> * creating a platform (or whatever-) specific code bundle by a tool that

Alf P. Steinbach

unread,
Jan 21, 2016, 6:46:14 PM1/21/16
to
On 1/22/2016 12:23 AM, Dmitry Chichkov wrote:
> Hi Alf,
>
> Yes, it is still necessary to select the correct platform-specific
> headers. And the tool like cmake, omake, etc would be the standard
> way of doing it. The problem is, after you've included a

Please don't top

> platform-specific definition - for example arm/math.h, you have
> duplicate function/type/template definitions in the common code (for

post.

> example math.h) and in the platform-specific code.
>
> This can be solved, if you'd simply implement the whole set of
> function in every platform-specific file, redirecting every
> unimplemented call to common routine. But if the number of supported
> platforms is large, this adds a lot of code/maintenance. There are

It's not how things are

> ways to address that with preprocessor or templates, but it either
> forces one to mangle function names or it supports C++ only and
> requires to template every function/type, etc. It seems like this

done on Use

> inline namespace trick gives cleaner alternative, but I haven't seen
> it in practice, and I'm not sure what are the potential pitfalls...
>
> Cheers, Dmitry
>

net.

See e.g. <url:
http://www.csse.monash.edu.au/courseware/cse3400/2006/c++-faq/how-to-post.html#faq-5.4>
for more info about how to post. In particular check out the 4th bullet
point.

That said, I have never had a problem with platform-specific headers
colliding with headers used by general code. There have been problems
like ungood macros and such, handled by the usual compiler firewall
technique. But nothing like a platform specific <math.h> colliding with
the standard <math.h>.

Dmitry Chichkov

unread,
Jan 21, 2016, 8:49:01 PM1/21/16
to
On Thursday, January 21, 2016 at 3:46:14 PM UTC-8, Alf P. Steinbach wrote:
> See e.g. <url:
> http://www.csse.monash.edu.au/courseware/cse3400/2006/c++-faq/how-to-post.html#faq-5.4>
> for more info about how to post. In particular check out the 4th bullet
> point.
>
> That said, I have never had a problem with platform-specific headers
> colliding with headers used by general code. There have been problems
> like ungood macros and such, handled by the usual compiler firewall
> technique. But nothing like a platform specific <math.h> colliding with
> the standard <math.h>.
>
> Cheers & hth.,
>
> - Alf

I'm sorry if the answer to that is obvious, but what usual compiler firewall technique do you have in mind? Would it support inlining?

Dmitry

Alf P. Steinbach

unread,
Jan 21, 2016, 9:08:04 PM1/21/16
to
Just separate compilation, including the troublesome headers in
separately compiled sources.

The pimpl idiom (see <url: http://www.gotw.ca/publications/mill05.htm>)
is in support of a special case of that.

One doesn't need to use pimpl, however, to have a compilation firewall.

The main thing is that all those implementation details are isolated,
not visible to the rest of the system.

For example, one may express a template in terms of a non-template
implementation. Client code then uses the type safe template code
provided by a clean header. The not so type safe implementation, that
instead relies on conventions etc., is separately compiled.



> Would it support inlining?

Nope, not all the way. :(

It's possible that whole program optimization, a.k.a. link time
optimization, now supported by at least g++ and MSVC, can help further
with the optimization.

But as with any optimization issue, it can be a good idea to MEASURE
first, and only if that says it's necessary, expend a lot of work on the
optimization.

Öö Tiib

unread,
Jan 22, 2016, 2:41:44 AM1/22/16
to
On Friday, 22 January 2016 04:08:04 UTC+2, Alf P. Steinbach wrote:
>
> One doesn't need to use pimpl, however, to have a compilation firewall.

Yes, the opaque types are also used in C.

In C++ we can use opaque inner or friend class to remove the declarations
of private member functions from header file. It is useful when
additional indirection from pimpl is unneeded and we do not care
of fire-walling declarations of data members.

Inlining depends if linker does it or does not so it is quality of
implementation issue. The keyword 'inline' is unfortunately misleading.

dmitry....@daqri.com

unread,
Jan 22, 2016, 1:39:59 PM1/22/16
to
On Thursday, January 21, 2016 at 6:08:04 PM UTC-8, Alf P. Steinbach wrote:
> The pimpl idiom (see <url: http://www.gotw.ca/publications/mill05.htm>)
> is in support of a special case of that.
>
> One doesn't need to use pimpl, however, to have a compilation firewall.
>
> The main thing is that all those implementation details are isolated,
> not visible to the rest of the system.
>
> For example, one may express a template in terms of a non-template
> implementation. Client code then uses the type safe template code
> provided by a clean header. The not so type safe implementation, that
> instead relies on conventions etc., is separately compiled.
>
>
>
> > Would it support inlining?
>
> Nope, not all the way. :(
>
> It's possible that whole program optimization, a.k.a. link time
> optimization, now supported by at least g++ and MSVC, can help further
> with the optimization.
>
> But as with any optimization issue, it can be a good idea to MEASURE
> first, and only if that says it's necessary, expend a lot of work on the
> optimization.
>
>
> Cheers & hth.,
>
> - Alf

Let's narrow it down to the case then the *design spec* *requires* static linking / reasonably efficient inlining of platform-specific code. And specifically *excludes* solutions that expect the compiler to use optimization hacks to statically resolve virtual/pimpl calls at a compile time.

There are 'CRTP' and 'traits' patterns that allow one to do it in C++. And preprocessor hacks. It looks like this inline namespace trick described here could be an alternative to these approaches. Question - does anyone see any potential pitfalls with this technique?

Öö Tiib

unread,
Jan 23, 2016, 6:40:40 AM1/23/16
to
I think that we do not actually need any virtual/pimpl calls.

If functions are or are not inlined is up to complier and linker
and can not be affected from C++ code (without using platform-specific
extensions).

>
> There are 'CRTP' and 'traits' patterns that allow one to do it in C++.
> And preprocessor hacks. It looks like this inline namespace trick
> described here could be an alternative to these approaches.

CRTP and traits patterns are not really meant for separating
platform-specific code from code that is common for all platforms
but for simplifying any compile-time meta-programming code.

> Question - does anyone see any potential pitfalls with this technique?

It can look as confusing as slicing code with preprocessor and unlike
when done with preprocessor it assumes that the platform-specific code
compiles on all platforms (that is rarely the case in practice).

I myself prefer simply to link to platform-specific implementation
file. Different files implement same thing for different platforms.
It is better because then there may be platform-specific extensions
to language used in platform-specific code if needed.

0 new messages