2

I have some C++ code that is automatically generated to wrap some C code.

The C code has a predictable structure with the exception that it has/has not a certain function.

Since the C++ code is derived from a description that does not have this information. I would like to use the template processor to decide if this function can be called.

small example:

struct SomeStruct{
  int indicatorMember;
};
extern "C" void someFun(struct SomeStruct* somePointer){
}



void someCPPcode(){
  SomeStruct s;
  // do something

  someMechanismToCall_someFunIfExists(&s);

  // do something other
}

How does someMechanismToCall_someFunIfExists have to look like, so that someCPPcode can be compiled/run in cases there someFun does exist and if it does not exist?

Is this even possible?

It would also be possible to decide if this function exists, if a certain member is part of a structure. so, if indicatorMember does exist, the function also exists.

vlad_tepesch
  • 6,681
  • 1
  • 38
  • 80
  • 5
    If your C++ code is automatically generated can't you include this logic in the generator itself? I.e. generate call only if it can find function in C source. – Dan M. Dec 04 '19 at 12:36
  • You might find some tips ins this link: [how-to-check-if-the-function-exists](https://stackoverflow.com/questions/8814705/how-to-check-if-the-function-exists-in-c-c/8814869#8814869) – hasi90 Dec 04 '19 at 12:40
  • 1
    Does this answer your question? [Is it possible to write a template to check for a function's existence?](https://stackoverflow.com/questions/257288/is-it-possible-to-write-a-template-to-check-for-a-functions-existence) – Dan M. Dec 04 '19 at 12:41
  • If you have some structure indicator method/field then there are SFINAE approaches in the linked question. – Dan M. Dec 04 '19 at 12:42
  • @DanM. the generator does not know the c source. it uses a definition language that does not include this information – vlad_tepesch Dec 04 '19 at 12:42
  • Do you control generator? Do you have the C-Header? – Jarod42 Dec 04 '19 at 15:07

2 Answers2

1

You might use overload with lower priority to solve your issue:

// "C-Header"
struct SomeStruct
{
  int indicatorMember;
};

// Present or not
extern "C" void someFun(struct SomeStruct* somePointer){

}

// Fallback
void someFun(...) { /*Empty*/ }

void someCPPcode()
{
  SomeStruct s;
  // do something

  someFun(&s);

  // do something other
}

it would also be possible to decide if this function exists, if a certain member is part of a structure. so, if indicatorMember does exist, the function also exists.

There are several ways to detect presence of member, such as use of std::experimental::is_detected.

but outside template, you still have issue:

decltype(auto) someFunIfExists([[maybe_unused]] SomeStruct* p)
{
    if constexpr (has_someFunc<SomeStruct>::value) {
        return someFun(p); // Not discarded as you might expect -> Error
    }
}

as if constexpr (false) { static_assert(false); } is invalid).

So you have to wrap the function inside template:

template <typename T>
decltype(auto) someFunIfExists([[maybe_unused]] T* p)
{
    if constexpr (has_someFunc<T>::value) {
        return someFun(p);
    }
}

void someCPPcode(){
  SomeStruct s;
  // do something

  someFunIfExists(&s);

  // do something other
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • The problem with this is that it's still a question of what functions are declared and not of what functions have definitions. You would somehow have to make all declarations of the C library function disappear if the C library doesn't define the function… – Michael Kenzel Dec 04 '19 at 14:40
  • Unsure of the "input" (Do we have c-header, does OP generates C++ code or not, ...) – Jarod42 Dec 04 '19 at 15:08
0

The question of whether there's a definition of some symbol with external linkage or not is inherently a question that can only be answered during linking. There is no way for the compiler to know during compilation of an individual C++ source file whether there is going to be a definition of some external function somewhere else. SFINAE can, in the best case, check for whether a certain function is declared. It is impossible for SFINAE to determine whether the linker will find a definition of that function later on.

If the C library comes with headers that you can include in C++ and that declare the functions in question only if the particular version of the C library defines them, you can use an appraoch like the one described in Jarod42's answer.

Otherwise, the best thing I can think of to do here would be to define default implementations of your functions as weak symbols that are always defined, e.g.:

struct SomeStruct
{
    int indicatorMember;
};

extern "C" void someFun(SomeStruct* somePointer) __attribute__((weak))
{
    // do whatever this should do in case the C library does not define this function
}

Weak symbols are no part of Standard C++, so the exact mechanism for doing this depends on your compiler and platform. The above would be an example for GCC. MSVC has an undocumented linker flag /alternatename that allows to provide default definitions for a symbol, see this answer.

During linking, if the linker finds a non-weak definition of the same symbol coming from your C library, it will pick that one, otherwise it will pick your default implementation…

Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39