How to detect whether there is a specific member variable in class?
Another way is this one, which relies on SFINAE for expressions too. If the name lookup results in ambiguity, the compiler will reject the template
template<typename T> struct HasX {
struct Fallback { int x; }; // introduce member name "x"
struct Derived : T, Fallback { };
template<typename C, C> struct ChT;
template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1];
template<typename C> static char (&f(...))[2];
static bool const value = sizeof(f<Derived>(0)) == 2;
};
struct A { int x; };
struct B { int X; };
int main() {
std::cout << HasX<A>::value << std::endl; // 1
std::cout << HasX<B>::value << std::endl; // 0
}
It's based on a brilliant idea of someone on usenet.
Note: HasX checks for any data or function member called x, with arbitrary type. The sole purpose of introducing the member name is to have a possible ambiguity for member-name lookup - the type of the member isn't important.
How to detect whether there is a specific PRIVATE member variable in class?
Well... not sure about correctness and limits of this solution... but...
If you define an helper struct with an x
element accessible
struct check_x_helper
{ int x; };
you can write a template struct that inherit from both check_x_helper
and the class you want to see if contain a x
member
template <typename T>
struct check_x : public T, check_x_helper
Inside check_x
you can declare (declare only: are used inside a decltype()
) as follows
template <typename U = check_x, typename = decltype(U::x)>
static constexpr std::false_type check (int);
static constexpr std::true_type check (long);
Observe the first one, the template one: when the checked class (T
) contains an x
member, the decltype(U::x)
is ambiguous because x
is inherited from both T
and check_x_helper
, so this function is SFINAE discarded.
On contrary, when T
doesn't contains an x
member, there isn't an ambiguity, the decltype(U::x)
is the type of check_x_helper::x
(int
) and the first check()
function remain enabled.
Now you need something as
using type = decltype(check(0));
static constexpr auto value = type::value;
to call check(0)
(the int
parameter express the preference to the template version) and save the detected value
in a static constexpr
variable.
The following is a full compiling example
#include <iostream>
#include <utility>
class foo
{ int x; };
struct bar
{ };
struct check_x_helper
{ int x; };
template <typename T>
struct check_x : public T, check_x_helper
{
template <typename U = check_x, typename = decltype(U::x)>
static constexpr std::false_type check (int);
static constexpr std::true_type check (long);
using type = decltype(check(0));
static constexpr auto value = type::value;
};
int main()
{
std::cout << check_x<foo>::value << std::endl;
std::cout << check_x<bar>::value << std::endl;
}
Drawback of this solution: decltype(U::x)
fail (ambiguity) also when T
declare x
as a method or as a using
type. So given
class foo
{ int x () { return 0;} ; };
or
class foo
{ using x = int; };
from check_x<foo>::value
you obtain 1
.
How to detect whether there is actually a specific member variable in class?
The problem is that HasX
only checks if the name x
exists. The ...
gets selected if &C::x
is ambiguous (which happens if it matches both in Fallback
and T
). The ChT<>
overload gets selected only if &C::x
is exactly Fallback::x
. At no point are we actually checking the type of T::x
- so we never actually check if x
is a variable or function or whatever.
The solution is: use C++11 and just check that &T::x
is a member object pointer:
template <class T, class = void>
struct HasX
: std::false_type
{ };
template <class T>
struct HasX<T,
std::enable_if_t<
std::is_member_object_pointer<decltype(&T::x)>::value>
>
: std::true_type { };
If &T::x
doesn't exist, substitution failure and we fallback to the primary template and get false_type
. If &T::x
exists but is an overloaded name, substitution failure. If &T::x
exists but is a non-overloaded function, substitution failure on enable_if_t<false>
. SFINAE for the win.
That works for all of these types:
struct A {
void x()
{
}
void x(int)
{
}
};
struct B { int X; };
struct C { int x; };
struct D { char x; };
int main() {
static_assert(!HasX<A>::value, "!");
static_assert(!HasX<B>::value, "!");
static_assert(HasX<C>::value, "!");
static_assert(HasX<D>::value, "!");
}
C++17 how to test class has a member variable?
If you are stuck in c++17, there is some infrastructure that you can add to make detection like this much easier.
Detection-idiom
The most reusable/consistent way to detect features like this is via the Detection idiom, which leverages SFINAE through std::void_t
in a template.
This can be taken verbatim from std::experimental::is_detected
's page from cppreference. This effectively offers C++17 the ability to detect features in a way that is similiar to C++20's concepts; and the infrastructure can be reused easily for just about any detection.
The basics of what you would need are:
#include <type_traits>
namespace detail {
template <class Default, class AlwaysVoid,
template<class...> class Op, class... Args>
struct detector {
using value_t = std::false_type;
using type = Default;
};
template <class Default, template<class...> class Op, class... Args>
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
using value_t = std::true_type;
using type = Op<Args...>;
};
} // namespace detail
struct nonesuch{};
template <template<class...> class Op, class... Args>
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
Note: The above infrastructure can be reused for any detection. It is a very useful reusable tool in C++17.
With is_detected
, all you need is a detector, which is simply a template alias that evaluates to a decltype
expression of something that may, or may not, exist.
So in your case, to conditionally detect the presence of T::extra
, you can do this with a simple detector like:
template <typename T>
using detect_extra = decltype(T::extra);
Putting it all together now, you can use this detector to conditionally toggle the branch:
if constexpr (is_detected<detect_extra,T>::value) {
// Only do code if 'T' has 'T::extra' (e.g. 'S')
} else {
// Only do code if 'T' does not have 'T::extra' (e.g. 'V')
}
Live Example
If equivalent conversion to a specific type is important, such as extra
needing to be convertible to int
, you can also use is_detected_convertible
and use the detector to check for if the result can be convertible to the desired type. Using the same cppreference page again, you can define is_detected_convertible
as:
template <template<class...> class Op, class... Args>
using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;
template <class To, template<class...> class Op, class... Args>
using is_detected_convertible = std::is_convertible<detected_t<Op, Args...>, To>;
Which allows the check to instead be:
if constexpr (is_detected_convertible<int, detect_extra, T>::value) {
// Only do code if 'T' has 'T::extra' convertible to int (e.g. 'S')
} else {
// Only do code if 'T' does not have 'T::extra', or is not int
}
Live Example
Concepts (C++20+ only)
If you have access to c++20 and beyond, concept
s make this much simpler -- since you can simply use a concept
+ requires
clause like:
#include <concepts> // std::same_as
template <typename T>
concept HasExtra = requires(T) {
{T::extra} -> std::same_as<int>;
};
if constexpr (HasExtra<T>) {
// Only do code if 'T' has 'T::extra' and is 'int' (e.g. 'S')
} else {
// Only do code if 'T' does not have 'T::extra' (e.g. 'V')
}
Live Example
How to check if a member name (variable or function) exists in a class, with or without specifying type?
C++03
#define HasMember(NAME) \
template<class Class, typename Type = void> \
struct HasMember_##NAME \
{ \
typedef char (&yes)[2]; \
template<unsigned long> struct exists; \
template<typename V> static yes Check (exists<sizeof(static_cast<Type>(&V::NAME))>*); \
template<typename> static char Check (...); \
static const bool value = (sizeof(Check<Class>(0)) == sizeof(yes)); \
}; \
template<class Class> \
struct HasMember_##NAME<Class, void> \
{ \
typedef char (&yes)[2]; \
template<unsigned long> struct exists; \
template<typename V> static yes Check (exists<sizeof(&V::NAME)>*); \
template<typename> static char Check (...); \
static const bool value = (sizeof(Check<Class>(0)) == sizeof(yes)); \
}
Usage: Simply invoke the macro with whatever member you want to find:
HasMember(Foo); // Creates a SFINAE `class HasMember_Foo`
HasMember(i); // Creates a SFINAE `class HasMember_i`
Now we can utilize HasMember_X
to check X
in ANY class
as below:
#include<iostream>
struct S
{
void Foo () const {}
// void Foo () {} // If uncommented then type should be mentioned in `HasMember_Foo`
int i;
};
int main ()
{
std::cout << HasMember_Foo<S, void (S::*) () const>::value << "\n";
std::cout << HasMember_Foo<S>::value << "\n";
std::cout << HasMember_i<S, int (S::*)>::value << "\n";
std::cout << HasMember_i<S>::value << "\n";
}
Catches:
- In case of methods, if we don't mention the type then the
class
must not have overloaded methods. If it has then this trick fails.
i.e. even though the named member is present more than once, the result will befalse
. - If the member is part of base class, then this trick fails; e.g. if
B
is base ofS
&void B::Bar ()
is present, thenHasMember_Bar<S, void (B::*)()>::value
orHasMember_Bar<S, void (S::*)()>::value
orHasMember_Bar<S>::value
will givefalse
Check if a member variable exists in an Object from superClass?
One solution would be to have a method in the superclass called getProperty
which can be called from any instance once the presence of the property is verified. In the superclass, the method can return null or throw an exception; override it in the subclass to return the actual property. Like so:
class SuperClass
{
protected boolean hasProperty;
protected Property getProperty()
{
throw new UnsupportedOperationException();
}
}
class SubOne extends SuperClass
{
protected Property prop;
SubOne()
{
this.hasProperty=true;
this.prop=new Property();
}
@Override
protected Property getProperty()
{
return prop;
}
}
class SubTwo extends SuperClass
{
SubTwo()
{
this.hasProperty=false;
}
}
And the code for the iteration would be as follows:
if (superObj.hasProperty)
System.out.println(superObj.getProperty().something);
else
System.out.println("Something");
The advantage of this over a template method is that it works for any application of the properties without needing to be changed.
Templated check for the existence of a class member function?
Yes, with SFINAE you can check if a given class does provide a certain method. Here's the working code:
#include <iostream>
struct Hello
{
int helloworld() { return 0; }
};
struct Generic {};
// SFINAE test
template <typename T>
class has_helloworld
{
typedef char one;
struct two { char x[2]; };
template <typename C> static one test( decltype(&C::helloworld) ) ;
template <typename C> static two test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
int main(int argc, char *argv[])
{
std::cout << has_helloworld<Hello>::value << std::endl;
std::cout << has_helloworld<Generic>::value << std::endl;
return 0;
}
I've just tested it with Linux and gcc 4.1/4.3. I don't know if it's portable to other platforms running different compilers.
Check if a class has a member function of a given signature
I'm not sure if I understand you correctly, but you may exploit SFINAE to detect function presence at compile-time. Example from my code (tests if class has member function size_t used_memory() const).
template<typename T>
struct HasUsedMemoryMethod
{
template<typename U, size_t (U::*)() const> struct SFINAE {};
template<typename U> static char Test(SFINAE<U, &U::used_memory>*);
template<typename U> static int Test(...);
static const bool Has = sizeof(Test<T>(0)) == sizeof(char);
};
template<typename TMap>
void ReportMemUsage(const TMap& m, std::true_type)
{
// We may call used_memory() on m here.
}
template<typename TMap>
void ReportMemUsage(const TMap&, std::false_type)
{
}
template<typename TMap>
void ReportMemUsage(const TMap& m)
{
ReportMemUsage(m,
std::integral_constant<bool, HasUsedMemoryMethod<TMap>::Has>());
}
Related Topics
Significance of -Pthread Flag When Compiling
Fastest Method of Screen Capturing on Windows
How to Generate Different Random Numbers in a Loop in C++
How to Make Thread Sleep Less Than a Millisecond on Windows
Operator Precedence VS Order of Evaluation
Undefined Reference to Static Constexpr Char[]
How to Have Functions Inside Functions in C++
Why Isn't Vector≪Bool≫ a Stl Container
Shared_Ptr to an Array: Should It Be Used
Difference Between Private and Protected Members of C++ Classes
Rules For C++ String Literals Escape Character