38

Certain situations in my code, I end up invoking the function only if that function is defined, or else I should not. How can I achieve this?

like:
if (function 'sum' exists ) then invoke sum ()

Maybe the other way around to ask this question is how to determine if function is defined at runtime and if so, then invoke?

user438383
  • 5,716
  • 8
  • 28
  • 43
Whoami
  • 13,930
  • 19
  • 84
  • 140
  • 3
    you'd have to use some sort of loadable library support, eg dlopen – Anycorn Jan 11 '12 at 05:47
  • 2
    How, exactly, do you propose to get into a situation where you want to call `sum` but aren't sure whether it exists? You should know whether it exists; you're the one writing the code! – Karl Knechtel Jan 11 '12 at 06:14
  • 1
    You really should explain why are you asking. In what context do you need that? I never needed that in 35 years of coding, in any compiled language.... – Basile Starynkevitch Jan 11 '12 at 06:21
  • i get the function name as a parameter from command line, and have to execute if exists. – Whoami Jan 11 '12 at 06:21
  • 3
    @whoami: in that case you need to do something like `if(string(argv[1]) == "sum") { sum(); }`. – Naveen Jan 11 '12 at 06:24
  • @whoami that should be said in the question. Please edit it suitably. I made an addenda to my reply. – Basile Starynkevitch Jan 11 '12 at 06:32
  • @Naveen But in case of sum() is not defined then it wont work, am i correct? – Whoami Jan 11 '12 at 06:35
  • Again, you have to define a suitable subset of functions to be so called. It would contain `sum` because you know that `sum` is defined and is sensible to call this way. – Basile Starynkevitch Jan 11 '12 at 07:03
  • possible duplicate of [Can I re-define a function or check if it exists?](http://stackoverflow.com/questions/6916772/can-i-re-define-a-function-or-check-if-it-exists) (although this is tagged C++) – Antonio Mar 19 '15 at 14:03
  • Possible duplicate of [Is it possible to write a C++ template to check for a function's existence?](http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence) – usr1234567 Jul 09 '16 at 19:10

11 Answers11

21

Using GCC you can:

void func(int argc, char *argv[]) __attribute__((weak)); // weak declaration must always be present

// optional definition:
/*void func(int argc, char *argv[]) { 
    printf("FOUND THE FUNCTION\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("did not find the function\n");
    }
}

If you uncomment func it will run it otherwise it will print "did not find the function\n".

pixelgrease
  • 1,940
  • 23
  • 26
  • 2
    I translated the original Spanish text to English to prevent this response from being flagged for non-English content per SO [non-English guidelines](https://meta.stackoverflow.com/questions/297673/how-do-i-deal-with-non-english-content). The original text, "ENCONTRE LA FUNC" and "no encontre la func", is not clear to some English speakers. – pixelgrease Jan 31 '23 at 18:08
21

When you declare 'sum' you could declare it like:

#define SUM_EXISTS
int sum(std::vector<int>& addMeUp) {
    ...
}

Then when you come to use it you could go:

#ifdef SUM_EXISTS
int result = sum(x);
...
#endif

I'm guessing you're coming from a scripting language where things are all done at runtime. The main thing to remember with C++ is the two phases:

  • Compile time
    • Preprocessor runs
    • template code is turned into real source code
    • source code is turned in machine code
  • runtime
    • the machine code is run

So all the #define and things like that happen at compile time.

....

If you really wanted to do it all at runtime .. you might be interested in using some of the component architecture products out there.

Or maybe a plugin kind of architecture is what you're after.

matiu
  • 7,469
  • 4
  • 44
  • 48
  • 3
    It's incredibly stupid that C++ doesn't already include such a pragma in the standard. C++ header files typically contain a zillion hacks to deal with this. A giid spec could even be type-specific. #ifhave(sum(std::vector)). I'd scrap all of C++11 just for that one feature... – Erik Aronesty Feb 02 '15 at 14:10
  • 1
    In reply to @ErikAronesty - I'm now moving away from c++ to [rust](https://www.rust-lang.org/) - I'm finding it a lot more fun :) – matiu Aug 27 '19 at 23:49
  • You linked the same site twice, was that intentional? Anyway the link was dead, I've updated it with the current version. – Fabio says Reinstate Monica Jun 16 '22 at 13:02
  • Thanks @FabiosaysReinstateMonica it was not intentional. I updated the component architecture link. – matiu Jul 03 '22 at 23:22
19

While other replies are helpful advices (dlsym, function pointers, ...), you cannot compile C++ code referring to a function which does not exist. At minimum, the function has to be declared; if it is not, your code won't compile. If nothing (a compilation unit, some object file, some library) defines the function, the linker would complain (unless it is weak, see below).

But you should really explain why you are asking that. I can't guess, and there is some way to achieve your unstated goal.

Notice that dlsym often requires functions without name mangling, i.e. declared as extern "C".

If coding on Linux with GCC, you might also use the weak function attribute in declarations. The linker would then set undefined weak symbols to null.

addenda

If you are getting the function name from some input, you should be aware that only a subset of functions should be callable that way (if you call an arbitrary function without care, it will crash!) and you'll better explicitly construct that subset. You could then use a std::map, or dlsym (with each function in the subset declared extern "C"). Notice that dlopen with a NULL path gives a handle to the main program, which you should link with -rdynamic to have it work correctly.

You really want to call by their name only a suitably defined subset of functions. For instance, you probably don't want to call this way abort, exit, or fork.

NB. If you know dynamically the signature of the called function, you might want to use libffi to call it.

Pharap
  • 3,826
  • 5
  • 37
  • 51
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 4
    Another approach for C++ (though not C) SFINAE using templates: http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence – fredbaba Aug 01 '13 at 18:58
  • I have an abstraction that benefits from an operator overload. Thus the default operator is defined at compile time. If the operator overload exists I would like to detect it at runtime. – ergohack Dec 13 '16 at 18:21
  • @ergohack C++ overloading happens entirely during compile time and depends on symbol name mangling, which is not pinned down by the C++ language standard (it depends on the compiler used and its version). – datenwolf Apr 30 '21 at 18:59
15

I suspect that the poster was actually looking for something more along the lines of SFINAE checking/dispatch. With C++ templates, can define to template functions, one which calls the desired function (if it exists) and one that does nothing (if the function does not exist). You can then make the first template depend on the desired function, such that the template is ill-formed when the function does not exist. This is valid because in C++ template substitution failure is not an error (SFINAE), so the compiler will just fall back to the second case (which for instance could do nothing).

See here for an excellent example: Is it possible to write a template to check for a function's existence?

Community
  • 1
  • 1
fredbaba
  • 1,466
  • 1
  • 15
  • 26
10

use pointers to functions.

 //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"]();
 }
BruceAdi
  • 1,949
  • 1
  • 11
  • 8
  • 1
    This is clearly the solution to go for if I interpret the OP right and he's really trying to build a crude interactive shell. – arne Jan 11 '12 at 06:30
5

You can use #pragma weak for the compilers that support it (see the weak symbol wikipedia entry).

This example and comment is from 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)();
}

you can use the weak pragma to force the linker to ignore unresolved symbols [..] the program compiles and links whether or not debug() is actually defined in any object file. When the symbol remains undefined, the linker usually replaces its value with 0. So, this technique can be a useful way for a program to invoke optional code that does not require recompiling the entire application.

matiu
  • 7,469
  • 4
  • 44
  • 48
mihai
  • 4,592
  • 3
  • 29
  • 42
  • 1
    for me this compiles in clang, but the linker throws an error: `"debug()", referenced from: _debugfunc in test-fc106e.o`. `ld: symbol(s) not found for architecture x86_64` – kritzikratzi Aug 07 '17 at 11:14
5

If you know what library the function you'd like to call is in, then you can use dlsym() and dlerror() to find out whether or not it's there, and what the pointer to the function is.

Edit: I probably wouldn't actually use this approach - instead I would recommend Matiu's solution, as I think it's much better practice. However, dlsym() isn't very well known, so I thought I'd point it out.

Timothy Jones
  • 21,495
  • 6
  • 60
  • 90
3

So another way, if you're using c++11 would be to use functors:

You'll need to put this at the start of your file:

#include <functional>

The type of a functor is declared in this format:

std::function< return_type (param1_type, param2_type) >

You could add a variable that holds a functor for sum like this:

std::function<int(const std::vector<int>&)> sum;

To make things easy, let shorten the param type:

using Numbers = const std::vectorn<int>&;

Then you could fill in the functor var with any one of:

A lambda:

sum = [](Numbers x) { return std::accumulate(x.cbegin(), x.cend(), 0); } // std::accumulate comes from #include <numeric>

A function pointer:

int myFunc(Numbers nums) {
    int result = 0;
    for (int i : nums)
        result += i;
    return result;
}
sum = &myFunc;

Something that 'bind' has created:

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);

Then finally to use it, it's a simple if statement:

if (sum)
    return sum(x);

In summary, functors are the new pointer to a function, however they're more versatile. May actually be inlined if the compiler is sure enough, but generally are the same as a function pointer.

When combined with std::bind and lambda's they're quite superior to old style C function pointers.

But remember they work in c++11 and above environments. (Not in C or C++03).

matiu
  • 7,469
  • 4
  • 44
  • 48
1

In C++, a modified version of the trick for checking if a member exists should give you what you're looking for, at compile time instead of runtime:

#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>();
}

Here's the output using clang:

sum exists for type N12_GLOBAL__N_11AE
sum does not exist for type N12_GLOBAL__N_11BE

I should point out that weird things happened when I used an int instead of A (sum() has to be declared before sum_test for the exists to work, so maybe exists isn't the right name for this). Some kind of template expansion that didn't seem to cause problems when I used A. Gonna guess it's ADL-related.

Vince
  • 11
  • 2
0

This answer is for global functions, as a complement to the other answers on testing methods. This answer only applies to global functions.

First, provide a fallback dummy function in a separate namespace. Then determine the return type of the function-call, inside a template parameter. According to the return-type, determine if this is the fallback function or the wanted function.

If you are forbidden to add anything in the namespace of the function, such as the case for std::, then you should use ADL to find the right function in the test.

For example, std::reduce() is part of c++17, but early gcc compilers, which should support c++17, don't define std::reduce(). The following code can detect at compile-time whether or not std::reduce is declared. See it work correctly in both cases, in compile explorer.

#include <numeric>

namespace fallback
{
    // fallback
    std::false_type reduce(...) { return {}; }

    // Depending on
    // std::recuce(Iter from, Iter to) -> decltype(*from)
    // we know that a call to std::reduce(T*, T*) returns T
    template <typename T, typename Ret = decltype(reduce(std::declval<T*>(), std::declval<T*>()))>
    using return_of_reduce = Ret;

    // Note that due to ADL, std::reduce is called although we don't explicitly call std::reduce().
    // This is critical, since we are not allowed to define any of the above inside std::
}

using has_reduce = fallback::return_of_reduce<std::true_type>;

// using has_sum = std::conditional_t<std::is_same_v<fallback::return_of_sum<std::true_type>, 
//                                                   std::false_type>,
//                                    std::false_type,
//                                    std::true_type>;

#include <iterator>
int main()
{
    if constexpr (has_reduce::value)
    {
        // must have those, so that the compile will find the fallback
        // function if the correct one is undefined (even if it never
        // generates this code).
        using namespace std;
        using namespace fallback;
        int values[] = {1,2,3};
        return reduce(std::begin(values), std::end(values));
    }
    return -1;
}

In cases, unlike the above example, when you can't control the return-type, you can use other methods, such as std::is_same and std::contitional.

For example, assume you want to test if function int sum(int, int) is declared in the current compilation unit. Create, in a similar fashion, test_sum_ns::return_of_sum. If the function exists, it will be int and std::false_type otherwise (or any other special type you like).

using has_sum = std::conditional_t<std::is_same_v<test_sum_ns::return_of_sum, 
                                                  std::false_type>,
                                   std::false_type,
                                   std::true_type>;

Then you can use that type:

if constexpr (has_sum::value) 
{
   int result;
   {
      using namespace fallback; // limit this only to the call, if possible.
      result = sum(1,2);
   }
   std::cout << "sum(1,2) = " << result << '\n';
}

NOTE: You must have to have using namespace, otherwise the compiler will not find the fallback function inside the if constexpr and will complain. In general, you should avoid using namespace since future changes in the symbols inside the namespace may break your code. In this case there is no other way around it, so at least limit it to the smallest scope possible, as in the above example

Michael Veksler
  • 8,217
  • 1
  • 20
  • 33
0

In c you can use array of function pointers

#include<stdio.h>
#include<string.h>

typedef struct i32_2arg{int a, b;}i32_2_arg;
typedef struct i32_arg{int a;}i32_arg;

void add(void*a,void*r){
  i32_2_arg* l = (i32_2_arg*)a;
  ((i32_arg*)r)->a = l->a+l->b;
}
void sub(void*a,void*r){}

char lFunNames[8][64] = {"add","sub",0};
void (*lFuns[8]) (void*,void*) = {&add,&sub,0};

void evalfun(char* lName, void* inargs,void* outargs){
  for(int i = 0; i < 8; i++ )
  if (!strcmp(lFunNames[i],lName)) (*lFuns[i])(inargs,outargs);
}

int main(){
  i32_2_arg ab ={2,3};
  i32_arg sum;
  evalfun("add",&ab,&sum);
  printf("if \"add\" exists, result is %d\n",sum.a);
  return 0;
}
mathreadler
  • 447
  • 5
  • 16