Ruslan
Ruslan

Reputation: 19150

Is there any way to check whether a function has been declared?

Suppose there's a library, one version of which defines a function with name foo, and another version has the name changed to foo_other, but both these functions still have the same arguments and return values. I currently use conditional compilation like this:

#include <foo.h>
#ifdef USE_NEW_FOO
#define trueFoo foo_other
#else
#define trueFoo foo
#endif

But this requires some external detection of the library version and setting the corresponding compiler option like -DUSE_NEW_FOO. I'd rather have the code automatically figure what function it should call, based on it being declared or not in <foo.h>.

Is there any way to achieve this in any version of C?

If not, will switching to any version of C++ provide me any ways to do this? (assuming the library does all the needed actions like extern "C" blocks in its headers)? Namely, I'm thinking of somehow making use of SFINAE, but for a global function, rather than method, which was discussed in the linked question.

Upvotes: 6

Views: 285

Answers (3)

TartanLlama
TartanLlama

Reputation: 65770

In C++ you can use expression SFINAE for this:

//this template only enabled if foo is declared with the right args
template <typename... Args>
auto trueFoo (Args&&... args) -> decltype(foo(std::forward<Args>(args)...))
{
    return foo(std::forward<Args>(args)...);
}

//ditto for fooOther
template <typename... Args>
auto trueFoo (Args&&... args) -> decltype(fooOther(std::forward<Args>(args)...))
{
    return fooOther(std::forward<Args>(args)...);
}

Upvotes: 4

user1233963
user1233963

Reputation: 1490

In C++ you can do something like this:

#include <iostream>
#include <type_traits>

//#define DEFINE_F

#ifdef DEFINE_F
void f()
{

}
#endif

namespace
{
    constexpr struct special
    {
      std::false_type operator()() const;
    }f; 
}

struct checkForF
{
    static const constexpr auto value = std::conditional< std::is_same<std::false_type, decltype(::f())>::value, std::false_type, std::true_type >::type();
};

int main()
{
    std::cout << checkForF::value << std::endl;
}

ideone

Please note I only handle f without any parameters.

Upvotes: 0

Mike Robinson
Mike Robinson

Reputation: 8995

If you are statically linking to a function, in most versions of C++, the name of the function is "mangled" to reflect its argument list. Therefore, an attempt to statically link to the library, by a program with an out-of-date .hpp file, will result in an "unknown symbol" linker-error.

In the C language, there's no metadata of any kind which indicates what the argument list of any exported function actually is.

Realistically, I think, you simply need to be sure that the .h or .hpp files that you're using to link to a library, actually reflect the corresponding object-code within whatever version of that library you are using. You also need to be sure that the Makefile (or "auto-make" process) will correctly identify any-and-all modules within your application which link-to that library and which therefore must be recompiled in case of any changes to it. (If it were me, I would recompile the entire application.) In short, you must see to it that this issue doesn't occur.

Upvotes: 0

Related Questions