0

The following code shows class A, B, and C. An A is the ctor argument to B and C.

Macro X conditionally creates either an A or a B instance.

#include <iostream>

class A
{
};

class B
{
public:
  B( const A& a ) : a_( a ) { std::cout << __FUNCTION__ << std::endl; }
private:
  const A& a_;
};

class C
{
public:
  C( const A& a, const std::string& file, int line )
    : b_( ( (std::cout << "@ " << file << ":" << line << std::endl), a ) )
  {
    std::cout << "After" << std::endl;
  }
private:
  B b_;
};

#undef DEBUG
#ifdef DEBUG
#define X( Z ) B b##Z( Z )
#else
#define X( Z ) C c##Z( Z, __FILE__, __LINE__ )
#endif

int main( int argc, char* argv[] )
{
  A a;
  B b( a );
  C c( a, __FILE__, __LINE__ );
  X( a );
  return 0;
}

I was asked to rename B to SomethingElse and create a B macro such that all existing instances of B b( a ) becomes either a SomethingElse or a C.

I don't think this ask can be satisfied because SomethingElse and C constructors have different signatures, so I cannot just do:

#ifdef DEBUG
#define B SomethingElse
#else
#define B C
#endif

Are there C preprocessor experts out there who can confirm whether or not there is a way to satisfy the ask? Can a macro be created such that all existing instantiations of B can be swapped at compile-time to instantiations of SomethingElse or C? You can assume the second and third arguments to C will be __FILE__ and __LINE__.

6
  • 2
    What a mess, I would look for another job if I was you. Commented Jan 31, 2018 at 22:39
  • Can you give an example of what calls to B constrictors that become SomethingElse and C should get replaced by? Commented Jan 31, 2018 at 22:39
  • @Davislor if DEBUG defined, then B b( a ) becomes SomethingElse somethingelse_a( a ). If DEBUG undefined then B b( a ) becomes C c_a( a, __FILE__, __LINE__ ). Like I said: I don't think it is possible, but I'm open to suggestion. Commented Jan 31, 2018 at 22:48
  • 1
    @StoneThrow I think it was aimed at your job place practices and was in good faith. Commented Jan 31, 2018 at 22:58
  • @StoneThrow I clearly understood that you are enforced to do this crap, did not realize my comment is ambiguous (English is not my first language, sorry for misunderstanding) Commented Feb 1, 2018 at 13:40

2 Answers 2

4

This is fairly easy, once you realize that C++ inheritance implements an IS-A relation.

You define a new class realB<const str* FILE, int LINE>, which IS-A (derives from) either C or SomethingElse. The only small trick you need is a helper constexpr const char* to capture __FILE__, see here.

Now realB<FILE, LINE> has a ctor which takes only one parameter, A a, but if it inherits from C it can still pass (a, FILE, LINE) to C::C

Sign up to request clarification or add additional context in comments.

1 Comment

This is a very interesting solution. I use "template <int T>" style templatization (as opposed to "template <typename T>") so rarely it'd never pop to mind when it makes itself useful. I have a rudimentary proof of concept working based on your answer, and I think I can parlay this to apply to the actual situation. Thank you; this was a clever angle to approach this from.
0

I'm on my phone, so this is untested, but you might try:

#if DEBUG
#  define CREATEB(a) somethingelse(a)
#else
#  define CREATEB(a) C( (a), __FILE__, __LINE__ )
#endif

These should work on the right-hand-side of an auto or reference-to-base-class declaration.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.