Search code examples
c#c++directivepreprocessor

How to skip a C++ preprocessor directive in C#


I am trying to use the same class in C++ and C#. I am using preprocessor directives to scape code differences. However, I cannot skip C++ directives (as #include or #define) even when they are inside an #if #endif section.

The following code compiles in C++, but not in C#:

#if !NET
#pragma once
#include <string>      //<-- C# error CS1024: Preprocessor directive expected
#define public public: //<-- C# error CS1025: Single-line comment or end-of-line expected
#endif

#if NET
namespace A.B {
#else
namespace A::B {
   using namespace std;
#endif
   class C {
      string str;
      public C() {str = "test";}
   };
}

#if !NET
#undef public
#endif

Questions:

  • Why can I not do this?
  • Why C# preprocessor tries to understand #include or #define directives if they are inside an #if !NET section?
  • Is there anyway to do it?

EDIT:

Ouch! Rereading chapter 6.5.5 of the C# standard specification, I notice the following paragraph:

Any remaining conditional sections are skipped and no tokens, except those for pre-processing directives, are generated from the source code. Therefore skipped source code, except pre-processing directives, may be lexically incorrect. Skipped pre-processing directives shall be lexically correct but are not otherwise processed. Within a conditional section that is being skipped any nested conditional sections (contained in nested #if...#endif constructs) are also skipped.

  • So, ok, my first question is answered.
  • What about the second one: Why pre-processing directives shall be lexical correct?
  • However, does anybody know how to avoid this limitation? How to make the above code work?

Solution

  • Finally, I have found a method to solve this issue using two files:

    Note: It may not be the best idea, but I can't find a better one than this.

    /*** myfile.hpp ***/
    #pragma once
    
    #include <string>
    
    #define public public:
    #include "myfile.cs"
    #undef public
    
    /*** myfile.cs ***/
    #if NET
    namespace A.B {
    #else
    namespace A::B {
       using string = std::string;
    #endif
       class C {
          string str;
          public C() {str = "test";}
       };
    }
    

    With these two files, on C++ myfile.hpp should be included, and on C# only myfile.cs is needed.

    The idea is taken from here: https://stackoverflow.com/a/56839291/13087883