【问题标题】:c++ call c function if it does existc++调用c函数,如果它确实存在
【发布时间】:2019-12-04 12:32:43
【问题描述】:

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

C 代码具有可预测的结构,但它具有/没有特定功能。

由于 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 的外观如何,以便在someFun 确实存在且不存在的情况下可以编译/运行一些CPPcode?​​p>

这可能吗?

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

【问题讨论】:

标签: c++ sfinae


【解决方案1】:

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

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

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

有几种方法可以检测成员的存在,例如使用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
}

【讨论】:

  • 问题在于,它仍然是声明了哪些函数而不是定义了哪些函数的问题。如果 C 库没有定义函数,您将不得不以某种方式使 C 库函数的所有声明消失……
  • 不确定“输入”(我们是否有 c-header,OP 是否生成 C++ 代码,...)
【解决方案2】:

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

如果 C 库带有可以包含在 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 库中找到相同符号的非弱定义,它将选择那个,否则它将选择您的默认实现……

【讨论】:

    猜你喜欢
    • 2014-10-13
    • 1970-01-01
    • 1970-01-01
    • 2012-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-20
    相关资源
    最近更新 更多