1

C++11 allows to check, reasonably concisely, for the existence of a member: Is it possible to write a template to check for a function's existence?

Is it possible to check for the existence of a global function declaration (namespaced or not)?

Details: In my particular case, I'd like to check if my stdio.h implementation (#included) defines e.g., fprintf_unlocked (with the standard signature) and use that if it does, otherwise default to fprintf.

Community
  • 1
  • 1
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • If name exists, we can check its signature/ or if it can accept some parameter. – Jarod42 Feb 09 '16 at 14:52
  • @Jarod42 I'd like to check if `int ::fprintf_unlocked(FILE* , const char*, ...)` has been declared. How can I do that? – Petr Skocik Feb 09 '16 at 14:59
  • I'm having difficulty hunting down the docs for `fprintf_unlocked`. is it the same as `fprintf` except without the automatic thread safety on gnu libc? – jaggedSpire Feb 09 '16 at 15:01
  • @jaggedSpire gnu libc doesn't have it, but some other similar libraries do. That's just a detail, though. I might as well be checking for `void ::foobar(int)`. – Petr Skocik Feb 09 '16 at 15:05
  • 3
    Declare a function template of the same name and check which one will get called. Of course this pollutes your global namespace. – n. m. could be an AI Feb 09 '16 at 15:07
  • @n.m Thanks a lot. Worked like a charm. The non-templated functions gets precedence, so that solves my problem. – Petr Skocik Feb 09 '16 at 15:24

2 Answers2

3

A way to check existence of function, You may create following traits:

#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature)               \
    template <typename U>                                                   \
    class traitsName                                                        \
    {                                                                       \
    private:                                                                \
        template<typename T, T> struct helper;                              \
        template<typename T>                                                \
        static std::uint8_t check(helper<signature, &funcName>*);           \
        template<typename T> static std::uint16_t check(...);               \
    public:                                                                 \
        static                                                              \
        constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
    }

DEFINE_HAS_SIGNATURE(has_foo, foo, T*);
DEFINE_HAS_SIGNATURE(has_bar, bar, T*);

And then test it

has_foo<void(int)>::value

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 1
    Macro, barf ;) And `&funcName` doesn't work for overloaded names. – Jonathan Wakely Feb 09 '16 at 15:37
  • Ooh, actually it does work, sorry! The `helper` template is enough to coerce the function pointer to the right type. – Jonathan Wakely Feb 09 '16 at 16:04
  • 1
    @Jonathan Wakely I tried it and it did work with overloaded names. I guess it finds the right one that `helper` instantiates with, if such a function with `funcName` exists. Unfortunately, it completely fails to compile if there's if `funcName` isn't declared at all but it's no problem to declare (and not define) a bogus one. – Petr Skocik Feb 09 '16 at 16:06
  • Yes, it can check for the required signature, but assumes _some_ function with that name exists already. – Jonathan Wakely Feb 09 '16 at 16:53
  • @JonathanWakely: Not necessary clear in my demo, but it was the role of my `struct Dummy` to provide *dummy* overload to force existence of the name. – Jarod42 Feb 09 '16 at 17:04
  • @Jarod42 I sat down with it and made it a little more versatile so it now handles both members and nonmembers. Check it out if you'd like. – Petr Skocik Feb 23 '16 at 15:55
  • @PSkocik, sorry to ask about something posted so long ago, but I was wondering about the purpose of the signature parameter to the macro. What else besides T* would you ever expect to be used there? – Will Hawkins Nov 26 '20 at 13:57
0

I've made a hybrid traits generator macro that checks for either members or free standing functions.

This creates template traits classes that look whether a user supplied signature (first template arg) works with the name embedded in the traits class.

It looks for free-standing names if no second template param is supplied (Trait<Sig>::value), or for a member of the second template argument if the traits template is instantiated with two arguments (Trait<Sig,ClassToSearch>::value).

It can only search for free functions that were declared before the Traits template class was defined.

#define DEF_HAS_SIG(TraitsName, funcName) \
std::nullptr_t funcName(...); \
template<typename Sig, typename Type=void> class TraitsName { \
  typedef char yes[1];                                        \
  typedef char no [2];                                        \
  template <typename U, U> struct TypeCheck;                  \
  template <typename _1, typename _2 > static no  &chk(...);  \
  template <typename _1, typename _2> static                  \
    typename std::enable_if< std::is_same<void,_2>::value, yes&>::type chk(TypeCheck<_1, &funcName > *); \
  template <typename _1, typename _2> static yes& chk(TypeCheck<_1, &_2::funcName > *);                  \
public: static bool const value = sizeof(chk<Sig,Type>(0)) == sizeof(yes);                               \
};
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • (Apologies for the formatting. I don't write directly in C++ but rather generated it from a mini-language of mine that among other things abbreviates all the keywords, which means the original looks less clunky.) – Petr Skocik Feb 23 '16 at 15:51