-
-
Save maddouri/0da889b331d910f35e05ba3b7b9d869b to your computer and use it in GitHub Desktop.
// A compile-time method for checking the existence of a class member | |
// @see https://general-purpose.io/2017/03/10/checking-the-existence-of-a-cpp-class-member-at-compile-time/ | |
// This code uses "decltype" which, according to http://en.cppreference.com/w/cpp/compiler_support | |
// should be supported by Clang 2.9+, GCC 4.3+ and MSVC 2010+ (if you have an older compiler, please upgrade :) | |
// As of "constexpr", if not supported by your compiler, you could try "const" | |
// or use the value as an inner enum value e.g. enum { value = ... } | |
// check "test_has_member.cpp" for a usage example | |
/// Defines a "has_member_member_name" class template | |
/// | |
/// This template can be used to check if its "T" argument | |
/// has a data or function member called "member_name" | |
#define define_has_member(member_name) \ | |
template <typename T> \ | |
class has_member_##member_name \ | |
{ \ | |
typedef char yes_type; \ | |
typedef long no_type; \ | |
template <typename U> static yes_type test(decltype(&U::member_name)); \ | |
template <typename U> static no_type test(...); \ | |
public: \ | |
static constexpr bool value = sizeof(test<T>(0)) == sizeof(yes_type); \ | |
} | |
/// Shorthand for testing if "class_" has a member called "member_name" | |
/// | |
/// @note "define_has_member(member_name)" must be used | |
/// before calling "has_member(class_, member_name)" | |
#define has_member(class_, member_name) has_member_##member_name<class_>::value |
// usage example: check for the existence of a "sayHi" member ////////////////////////////////////// | |
// clang++ -std=c++11 -pedantic -Wall -Wextra test_has_member.cpp -o test_has_member && ./test_has_member | |
// g++ -std=c++11 -pedantic -Wall -Wextra test_has_member.cpp -o test_has_member && ./test_has_member | |
#include <iostream> // cout, endl | |
#include <iomanip> // std::boolalpha | |
#include "has_member.hpp" | |
struct A // has a "sayHi" member | |
{ | |
void sayHi() { std::cout << "Hi there!" << std::endl; } | |
}; | |
struct B // doesn't have a "sayHi" member | |
{ | |
void sayBye() { std::cout << "Bye bye!" << std::endl; } | |
}; | |
// define a "sayHi" "member checker" class | |
define_has_member(sayHi); | |
int main() | |
{ | |
using std::cout; | |
using std::endl; | |
cout << std::boolalpha; // display "true" or "false" for booleans | |
A a; | |
B b; | |
// check the existence of "sayHi" | |
cout << "has_member(A, sayHi) " << has_member(A, sayHi) << endl; | |
cout << "has_member(B, sayHi) " << has_member(B, sayHi) << endl; | |
cout << endl; | |
// same thing, using decltype on instances | |
cout << "has_member(decltype(a), sayHi) " << has_member(decltype(a), sayHi) << endl; | |
cout << "has_member(decltype(b), sayHi) " << has_member(decltype(b), sayHi) << endl; | |
return 0; | |
} |
Is it possible that
define_has_member
can be called for multiple times before usage?
If you are thinking about calling define_has_member
with the same member name multiple times in the same compilation unit, then that's unfortunately not possible because it would re-define the "checker" class (see http://coliru.stacked-crooked.com/a/704e9ea3732a26c2)
If you modify the template to take a dummy int and fill it with the COUNTER macro, rather than pasting ##member_name, it should allow you to use the same name multiple times in the translation unit.
Is there a way to verify existence of private members too in c++?
Is it possible to check if A has a function sayHi(int)? basically check signature also.
Is it possible to check if A has a function sayHi(int)? basically check signature also.
I'm assuming you mean a way to disambiguate sayHi(float)
from sayHi(int)
or sayHi(string)
I believe this will only work if the signature is hinted at via a template (i.e. a function template on the member sayHi<T>(T)
) because C++ gives no way to specify the overload except at the call site and the way yes_type
is defined here is not going to do that. Perhaps there is a more convoluted way of defining yes_type
to use std::declval
so that the disambiguation can happen. At a first glance, it is not obvious.
Is it possible that
define_has_member
can be called for multiple times before usage?