我的代码中的某些情况,我最终只在定义了该函数时调用该函数,否则我不应该。我怎样才能做到这一点?
like:
if (function 'sum' exists ) then invoke sum ()
可能是另一种方式来问这个问题是:如何确定函数是否在运行时定义,如果是,则调用。
答案 0 :(得分:12)
当您声明'sum'时,您可以声明它:
#define SUM_EXISTS
int sum(std::vector<int>& addMeUp) {
...
}
然后当你来使用它时你可以去:
#ifdef SUM_EXISTS
int result = sum(x);
...
#endif
我猜你是来自一种脚本语言,其中的一切都是在运行时完成的。使用C ++需要记住的主要问题是两个阶段:
因此所有#define
和类似的事情都发生在编译时。
...
如果您真的想在运行时完成所有操作......您可能有兴趣使用其中的一些component architecture products。
或许plugin kind of architecture就是你所追求的。
答案 1 :(得分:10)
使用函数指针。
//initialize
typedef void (*PF)();
std::map<std::string, PF> defined_functions;
defined_functions["foo"]=&foo;
defined_functions["bar"]=&bar;
//if defined, invoke it
if(defined_functions.find("foo") != defined_functions.end())
{
defined_functions["foo"]();
}
答案 2 :(得分:10)
虽然其他回复是有用的建议(dlsym
,函数指针,...),但无法编译 C ++代码引用不存在的函数。至少,该函数必须声明;如果不是,您的代码将无法编译。如果没有(编译单元,某个目标文件,某些库)定义该函数,链接器会抱怨(除非它很弱,见下文)。
但是你应该解释为什么要问这个问题。我无法猜测,并且有一些方法可以达到你未说明的目标。
请注意,dlsym
通常需要没有name mangling的函数,即声明为extern "C"
。
如果在使用GCC的Linux上进行编码,您也可以在声明中使用weak
function attribute。然后链接器将未定义的弱符号设置为null。
如果你从某个输入中获取函数名,你应该知道只有一部分函数应该以这种方式调用(如果你不小心调用任意函数,它会崩溃!)你会更明确地明确构造那个子集。然后,您可以使用std::map
或dlsym
(声明extern "C"
子集中的每个函数)。请注意,带有dlopen
路径的NULL
会为主程序提供一个句柄,您应该将其与-rdynamic
链接以使其正常工作。
你真的想通过他们的名字只调用一个适当定义的函数子集。例如,您可能不希望以abort
,exit
或fork
的方式调用。
NB。如果您知道动态被调用函数的签名,您可能需要使用libffi来调用它。
答案 3 :(得分:10)
我怀疑海报实际上是在寻找SFINAE检查/派遣的更多内容。使用C ++模板,可以定义模板函数,一个调用所需函数(如果存在)和一个不执行任何函数(如果函数不存在)。然后,您可以使第一个模板取决于所需的函数,以便在函数不存在时模板格式错误。这是有效的,因为在C ++中模板替换失败不是错误(SFINAE),因此编译器将回退到第二种情况(例如它什么都不做)。
请点击此处查看优秀示例:Is it possible to write a template to check for a function's existence?
答案 4 :(得分:8)
使用GCC你可以:
void func(int argc, char *argv[]) __attribute__((weak)); // weak declaration must always be present
// optional definition:
/*void func(int argc, char *argv[]) {
printf("ENCONTRE LA FUNC\n");
for(int aa = 0; aa < argc; aa++){
printf("arg %d = %s \n", aa, argv[aa]);
}
}*/
int main(int argc, char *argv[]) {
if (func){
func(argc, argv);
} else {
printf("no encontre la func\n");
}
}
如果取消注释func,它将运行它,否则它将打印&#34; no encontre la func \ n&#34;。
答案 5 :(得分:4)
如果您知道要调用的函数是哪个库,那么您可以使用dlsym()
和dlerror()
来确定它是否在那里,以及该函数的指针是什么是
编辑:我可能实际上不会使用这种方法 - 相反,我会推荐Matiu的解决方案,因为我认为这是更好的做法。但是,dlsym()
并不是很有名,所以我想我会指出它。
答案 6 :(得分:2)
另一种方式,如果你使用的是c ++ 11,那就是使用仿函数:
您需要将其放在文件的开头:
#include <functional>
仿函数的类型以这种格式声明:
std::function< return_type (param1_type, param2_type) >
你可以添加一个变量来保存一个类似于以下的算符:
std::function<int(const std::vector<int>&)> sum;
为了简化操作,请缩短参数类型:
using Numbers = const std::vectorn<int>&;
然后你可以用以下任何一个填充functor var:
一个lambda:
sum = [](Numbers x) { return std::accumulate(x.cbegin(), x.cend(), 0); } // std::accumulate comes from #include <numeric>
函数指针:
int myFunc(Numbers nums) {
int result = 0;
for (int i : nums)
result += i;
return result;
}
sum = &myFunc;
'bind'创造的东西:
struct Adder {
int startNumber = 6;
int doAdding(Numbers nums) {
int result = 0;
for (int i : nums)
result += i;
return result;
}
};
...
Adder myAdder{2}; // Make an adder that starts at two
sum = std::bind(&Adder::doAdding, myAdder);
然后最后使用它,这是一个简单的if语句:
if (sum)
return sum(x);
总之,仿函数是函数的新指针,但它们更通用。如果编译器足够确定,实际上可能会内联,但通常与函数指针相同。
当与std :: bind和lambda结合使用时,它们优于旧式C函数指针。
但请记住,它们适用于c ++ 11及更高版本的环境。 (不是在C或C ++ 03中)。
答案 7 :(得分:1)
您可以将#pragma weak
用于支持它的编译器(请参阅weak symbol维基百科条目)。
此示例和评论来自The Inside Story on Shared Libraries and Dynamic Loading:
#pragma weak debug
extern void debug(void);
void (*debugfunc)(void) = debug;
int main() {
printf(“Hello World\n”);
if (debugfunc) (*debugfunc)();
}
您可以使用弱pragma强制链接器忽略未解析 符号[..]程序编译并链接是否debug() 实际上是在任何目标文件中定义的。当符号仍然存在时 undefined,链接器通常用0替换它的值。所以,这个 技术可以是程序调用可选代码的有用方法 这不需要重新编译整个应用程序。
答案 8 :(得分:0)
在 C++ 中,用于检查成员是否存在的 the trick 的修改版本应该在编译时而不是运行时为您提供您正在寻找的内容:
#include <iostream>
#include <type_traits>
namespace
{
template <class T, template <class...> class Test>
struct exists
{
template<class U>
static std::true_type check(Test<U>*);
template<class U>
static std::false_type check(...);
static constexpr bool value = decltype(check<T>(0))::value;
};
template<class U, class = decltype(sum(std::declval<U>(), std::declval<U>()))>
struct sum_test{};
template <class T>
void validate_sum()
{
if constexpr (exists<T, sum_test>::value)
{
std::cout << "sum exists for type " << typeid(T).name() << '\n';
}
else
{
std::cout << "sum does not exist for type " << typeid(T).name() << '\n';
}
}
class A {};
class B {};
void sum(const A& l, const A& r); // we only need to declare the function, not define it
}
int main(int, const char**)
{
validate_sum<A>();
validate_sum<B>();
}
这是使用 clang 的输出:
sum exists for type N12_GLOBAL__N_11AE
sum does not exist for type N12_GLOBAL__N_11BE
我应该指出,当我使用 int 而不是 A 时发生了奇怪的事情(sum()
必须在 sum_test
之前声明才能使 exists
工作,所以可能 {{1 }} 不是正确的名称)。某种模板扩展,当我使用 A 时似乎不会引起问题。我猜它与 ADL 相关。