C(++): Replace function declaration with macros but not its invocations

I have a library I can’t change where some function is declared, implemented and used, in single file. Lots of other stuff is done in that same file. I want to override that single function to do another thing. The issue is that when I use renaming macro, all the places where that macro/function name is found are replaced, both declarations and invocations. I want some way to rename only declaration or invocations. Then I’ll be able to simply drop-in my own function under initial name as a replacement.

The code looks like this:

// library-module.cpp

int foo(int a, int b)  // declaration
{
    return a+b;
}

int bar()
{
    return foo(1, 2);  // invocation
}


// main.cpp

// MAGIC HAPPENS HERE
#include "library-module.cpp"

int foo(int a, int b) // drop-in replacement
{
    return a-b;
}

int main()
{
    return bar(); // should be -1, not 3
}

Another option would be to do a vice-versa operation: to replace all invocations to some other symbol, but not the declaration. Though it’s not preferred, because there might be other users of that function name in the wild.

Yet another option would be to do it in runtime, but I believe it’s not that great.

Thank you.

UPD1:

It’s c++.

Here are the actual function declaration, implementation and usage in the file.

What I wanted is to substitute a single line of the function set_scenario, not touching anything else, from my other app that uses all that app’s code. The idea was to keep the maintenance of all the code, except that very function, to the core team, and to handle this one myself, because i need some specific implementation. Thus I am including not the headers, but the implementation, and want such a dirty hack. Maybe I’m on the wrong way?

In the end I’ve made a fork, changed the line and settled with this, though I believe it would’ve been better if I didn’t do a fork, because it becomes way harder to get the changes.

Another thought that comes to my mind is possibly I’ve to make a patch for the function I’m to change and apply it on every build. This way it would be precisely known what was that single line that changed, and I would immediately know that the initial function changed if I had patch applying error. Maybe this is a better way of achieving the same thing?

And in the end, it was very interesting for me do deal with that using macros, because it’s rather black magic to me.

Thank you again.

Answer

It may or may not be possible depending on how exactly the function is defined and used.

Assuming the exact declaration and usage you’ve shown, you can do this:

#define foo(a, b) FOO_LOW(CAT(DETECT_, a) CAT(DETECT_, b))(a, b)

#define CAT(a, b) CAT_(a, b)
#define CAT_(a, b) a##b

#define DETECT_int ,

#define FOO_LOW(...) FOO_LOW_(__VA_ARGS__)
#define FOO_LOW_(a, ...) CAT(FOO_IMPL, __VA_OPT__(_DECL))

#define FOO_IMPL(a, b) replacement(a, b)
#define FOO_IMPL_DECL(a, b) foo(a, b)


constexpr int foo(int a, int b) {return a + b;}
constexpr int replacement(int a, int b) {return a - b;}

static_assert(foo(100, 10) == 90);

This implementation requires C++20, and additionally MSVC needs /Zc:preprocessor and Clang (13 and earlier, see bug) needs -Wno-gnu-zero-variadic-macro-arguments. It’s possible to implement with an earlier standard and without those flags, but the macro will be more convoluted.

This specific implementation has some limitations:

  • It checks if both arguments start with int, so if it happens in a function call, it will be incorrectly considered a declaration, e.g. foo(int(1), int(2)).
  • If an argument contains a , outside of ( ), you get a compilation error, e.g. foo(std::array{1,2}[0], 1).
  • If an argument begins with a punctuation, you get a compilation error, e.g. foo((1), (2)).