-2

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?
  • 2
    OT: [Why is "using namespace std;" considered bad practice?](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) Doing it in a header file is plain wrong (IMO) – Some programmer dude Jun 08 '23 at 16:17
  • I know. This is an example code. The goal is to ask about skipping C++ directives in C# writing a code as easy as possible. – Sergio Pérez Beltrán Jun 08 '23 at 16:23
  • PErhaps the C# "preprocessor" just doesn't work as the C++ preprocessor? What does its documentation say? – Some programmer dude Jun 08 '23 at 16:24
  • 2
    Also, when you get this to work, please never do that again! It's just bad, and no one sane would want to ever even look at code like that. – Some programmer dude Jun 08 '23 at 16:25
  • 1
    How do you define the macro? `#if !NET` is true if `NET` is defined like `#define NET` or `-D NET`. Assign some non zero value to it or use `#ifndef NET` – 273K Jun 08 '23 at 16:27
  • Given the massively different syntax it's almost universally a bad idea to even attempt this. – Charlieface Jun 08 '23 at 16:43
  • 1
    @273K `-D` defines the macro to `1` by default, I believe. – HolyBlackCat Jun 08 '23 at 17:27
  • @HolyBlackCat Good to know it, my command line arguments can be reduced. – 273K Jun 08 '23 at 18:19
  • Maybe I'm stupid, but I don't see why you would want to compile the same file as both C++ and C# - Why don't you just create two different files and compile each as their own language? – Jesper Juhl Jun 08 '23 at 19:51
  • I can see that a typo in one `#endif` could really mess things up, so requiring only valid directives seems reasonable. Also, in C++ it is specifically forbidden the use `#define` to modify keywords, like `private`. – BoP Jun 08 '23 at 20:57
  • @JesperJuhl I am developing a tool where frontend is C# and backend is C++ and both need some common classes. Nowadays I have two files for each common class, one for C++, other for C# and when I change something in one file, I need to remember to change in the other side. I am trying to mix both files in one to improve maintainability and traceability. – Sergio Pérez Beltrán Jun 09 '23 at 07:52

1 Answers1

0

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