c ++调用c函数,如果它确实存在

c++ call c function if it does exist

我有一些自动生成的 C++ 代码来包装一些 C 代码。

C 代码具有可预测的结构,但它 has/has 不是某个函数。

由于 C++ 代码源自没有此信息的描述。我想使用模板处理器来决定是否可以调用这个函数。

小例子:

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



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

  someMechanismToCall_someFunIfExists(&s);

  // do something other
}

someMechanismToCall_someFunIfExists 必须是什么样子,以便某些 CPPcode 可以是 compiled/run 在某些情况下 someFun 确实存在,如果它不存在?

这可能吗?

如果某个成员是结构的一部分,也可以确定此函数是否存在。 因此,如果 indicatorMember 确实存在,则该函数也存在。

是否有一个带有外部链接的符号的定义的问题本质上是一个只能在链接时才能回答的问题。在编译单个 C++ 源文件期间,编译器无法知道是否会在其他地方定义某个外部函数。在最好的情况下,SFINAE 可以检查某个函数是否声明。 SFINAE 无法确定链接器稍后是否会找到该函数的定义。

如果 C 库附带 headers,您可以将其包含在 C++ 中,并且仅当特定版本的 C 库定义了相关函数时才声明相关函数,您可以使用所描述的方法在 Jarod42 的回答中。

否则,我能想到的最好的办法是将函数的默认实现定义为始终定义的 weak symbols,例如:

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
}

弱符号不是标准 C++ 的一部分,因此执行此操作的确切机制取决于您的编译器和平台。以上是 GCC 的示例。 MSVC 有一个未记录的链接器标志 /alternatename,允许为符号提供默认定义,请参阅 this answer

在链接过程中,如果链接器发现来自您的 C 库的相同符号的 non-weak 定义,它将选择那个,否则它将选择您的默认实现…

您可以使用优先级较低的重载来解决您的问题:

// "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.

有几种方法可以检测成员是否存在,例如使用 std::experimental::is_detected

但是在模板之外,你仍然有问题:

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

因为 if constexpr (false) { static_assert(false); } 无效)。

因此您必须将函数包装在模板中:

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
}