4

I have seen usage of #ifdef macros ( example Eigen library ) to manage platform specific, but haven't seen any one use "inline namespace"s to manage platform specific code.

The github repo belows gives specific code and example usage. https://github.com/dchichkov/curious-namespace-trick/wiki/Curious-Namespace-Trick

I am wondering if it is a viable technique to use or if there are any gotchas that I am not able to see. Below is the code snippet :

#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; 
} 

Output :

$g++ func.cpp -Dplatform=common ; ./a.out common add

$ g++ func.cpp -Dplatform=arm ; ./a.out arm add

Tej
  • 61
  • 3
  • 2
    While it's good to link to the source, you should also copy-and-paste a minimal snippet of code here (and properly format it!) which demonstrates what you're describing. – Jonathon Reinhart Jan 22 '16 at 00:58
  • It's not used because inline namespaces is a new feature and isn't widely supported, but this scenario is one of the main reasons that they exist. It's not really curious or a trick. – Collin Dauphinee Jan 22 '16 at 01:21
  • @JonathonReinhart Updated with code snippet. – Tej Jan 22 '16 at 01:23
  • @CollinDauphinee I have seen it being used or mentioned for being used for versioning but not for choosing platform specific code, so the curiosity. – Tej Jan 22 '16 at 01:25
  • You can do same w/o `inline namespace`. Just make `common` and `arm` namescapes and put same functions there. Another way is to make them classes, not namespaces. Advantage - you can share common functions and override platform specific(for each platform). – Michael Nastenko Jan 22 '16 at 01:30
  • @MichaelNastenko, no you can't do this without inline namespace. – Tej Jan 25 '16 at 18:37
  • @Tej One of methods I describe, works perfectly in UE4. And it much more clear than this trick. – Michael Nastenko Jan 26 '16 at 00:59
  • @Tej I made simple [example](http://goo.gl/x3hNup) – Michael Nastenko Jan 26 '16 at 01:08
  • @MichaelNastenko this would suffice for simple example where you assume ArmMath and GenericMath have the same set of functions. Wouldn't work for the case where ArmMath is a subset of functions defined in GenericMath – Tej Jan 26 '16 at 19:41
  • @Tej As I said, there are two ways. And you can override only some functions. Here [example for namespaces](http://goo.gl/gbqmFt). And here [example for classes](http://goo.gl/HxeGs1). You still think it doesn't work? – Michael Nastenko Jan 26 '16 at 22:43
  • @MichaelNastenko yes it still doesn't work. If there is add() in Generic::dot(), even though you define Math to ArmMath, you would end up calling Generic::add() in Generic::dot() ( example : http://goo.gl/ulBgAi ) ), which is not intended. The idea is to call platform specific code if available. – Tej Jan 26 '16 at 23:54
  • @Tej Ofcouse your example doesn't work. You must use `Math::add` in `GenericMath::dot`. [Like this](http://goo.gl/WuGIMX) – Michael Nastenko Jan 27 '16 at 00:52
  • @Tej And [examples for namespaces](http://goo.gl/Yos564) – Michael Nastenko Jan 27 '16 at 07:19

2 Answers2

0

There are at least two ways to achieve same results. First one with namespaces. Second one - with static functions in classes.

With namespaces:

#include <stdio.h>

namespace GenericMath
{
    void add();
    void dot();
}

namespace ArmMath
{
    void add();

    using GenericMath::dot;
}

namespace GenericMath
{
    void add() 
    {
        printf("generic add");
    }

    void dot() 
    {
        Math::add();
        printf("generic dot");
    }
}

namespace ArmMath
{
    void add() 
    {
        printf("arm add");
    }

    using GenericMath::dot;
}

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

With classes:

#include <stdio.h>

class GenericMath
{
public:
    static void add();
    static void dot();
};

class ArmMath : public GenericMath
{
public:
    static void add();
};

void GenericMath::add() 
{
    printf("generic add");
}

void GenericMath::dot() 
{
  printf("generic dot");
  Math::add();
}

void ArmMath::add() 
{
  printf("arm add");
}

int main()
{
    Math::add();
    Math::dot();
    return 1;
}

IMO inline namespaces make code less readable and too verbose.

Michael Nastenko
  • 2,785
  • 1
  • 10
  • 14
0

Once issue is that unlike #ifdef, the compiler still compiles all the code that isn't for the current platform.

So you can't use it for dealing with platform-specific APIs.

TBBle
  • 1,436
  • 10
  • 27
  • Well, you can't avoid pre-processor completely. But with pre-processor only it'll be pretty hairy. Even in question `#define` is used to choose correct namespace. – Michael Nastenko Jan 29 '16 at 12:02
  • True, but in the given example, the pre-processor is choosing the enabled variant, but only taking the other ones out of the default lookup set, not hiding them completely from the compiler. That's probably a good thing in many cases (avoids bitrot on non-enabled paths, for example) but it does present a limitation. The question was specifically inline namespaces versus `#ifdef`. – TBBle Jan 29 '16 at 12:23
  • I don't see where question implies avoiding usage of `#ifdef` completely. I understood it as **pre-processor only** versus **pre-processor+inline namespace**. May be author can clarify it? – Michael Nastenko Jan 29 '16 at 12:48
  • The question was "gotchas in the given technique". The given technique relies on inline namespaces to cause static name resolution to find the desired platform-specific code, and contrasts it with the use of `#ifdef` in the Eigen library. – TBBle Jan 30 '16 at 06:57