我有一些自动生成的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
存在或不存在的情况下可以编译/运行一些CPP代码?
这甚至有可能吗?
如果某个成员是结构的一部分,也可以确定此功能是否存在。因此,如果indicatorMember
存在,则该函数也存在。
您可以使用优先级较低的重载来解决问题:
// "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
。
但是在模板之外,您仍然有问题:
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); }
关于是否存在具有外部链接的某些符号的定义,这本质上是一个只能在链接期间回答的问题。编译器无法在编译单个C ++源文件的过程中知道在其他地方是否将定义某些外部函数。在最好的情况下,SFINAE可以检查某个功能是否declared。 SFINAE无法确定链接器以后是否会找到该函数的定义。
如果C库带有可包含在C ++中的标头,并且仅在特定版本的C库定义了它们时才声明有问题的函数,您可以使用Jarod42的答案中所描述的方法。
否则,我想到的最好的事情是将函数的默认实现定义为始终定义的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
}
,例如:
weak symbols
弱符号不是Standard C ++的一部分,因此执行此操作的确切机制取决于您的编译器和平台。以上是GCC的示例。 MSVC具有未记录的链接器标记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
}
,该标记允许为符号提供默认定义,请参见/alternatename
。
在链接期间,如果链接器发现来自您的C库的同一符号的非弱定义,它将选择该符号,否则将选择您的默认实现…