ugmisc 0.2
Miscellaneous C++ header library
Loading...
Searching...
No Matches
member.hpp File Reference

Macros which declare templates for testing named members of types. More...

#include "ugmisc/typelist.hpp"
#include <utility>

Go to the source code of this file.

Classes

struct  ugmisc::call_foo_method< T >

Macros

#define UGMISC_NAMED_MEMBER_TYPE_TEST(TEMPLATENAME, ALIASNAME, HASMEMBERNAME, NAME)
#define UGMISC_MEMBER_TYPE_TEST(NAME)
#define UGMISC_NAMED_MEMBER_STATIC_METHOD_CALL(TEMPLATENAME, NAME)
#define UGMISC_MEMBER_STATIC_METHOD_CALL(NAME)

Detailed Description

Macros which declare templates for testing named members of types.

The macros allow templates to be created which can check for the existence of a named member type of any of a list of types, and templates which can check for the existence of a named static method of any of a list of types, and forward arguments to it.

Default types or callables may be provided when using the declared templates.

Macro Definition Documentation

◆ UGMISC_MEMBER_STATIC_METHOD_CALL

#define UGMISC_MEMBER_STATIC_METHOD_CALL ( NAME)
Value:
UGMISC_NAMED_MEMBER_STATIC_METHOD_CALL(member_call_##NAME, NAME)
#define UGMISC_NAMED_MEMBER_STATIC_METHOD_CALL(TEMPLATENAME, NAME)
Definition member.hpp:506

Equivalent to UGMISC_NAMED_MEMBER_STATIC_METHOD_CALL(member_call_NAME, NAME).

See the description of UGMISC_MEMBER_TYPE_TEST(NAME) for the pitfalls of using this.

◆ UGMISC_MEMBER_TYPE_TEST

#define UGMISC_MEMBER_TYPE_TEST ( NAME)
Value:
UGMISC_NAMED_MEMBER_TYPE_TEST(member_type_test_##NAME, member_type_##NAME, has_member_type_##NAME, NAME)
#define UGMISC_NAMED_MEMBER_TYPE_TEST(TEMPLATENAME, ALIASNAME, HASMEMBERNAME, NAME)
Definition member.hpp:277

This is equivalent to calling UGMISC_NAMED_MEMBER_TYPE_TEST(member_type_test_NAME, member_type_NAME, has_member_type_NAME, NAME).

The downside to this compared to directly using UGMISC_NAMED_MEMBER_TYPE_TEST, is that it is not obvious, without looking up the macro's definition or documentation, what declarations it makes. I personally would use this where a few macro calls were wanted in one place, and include a comment explaining the effect.

For example:

// Creates member_type_Foo< Type_or_type_list, Optional_Default >;
// has_member_type_Foo< Type_or_type_list >;
// member_type_Bar, has_member_type_Bar;
// member_type_Baz, has_member_type_Baz;
#define UGMISC_MEMBER_TYPE_TEST(NAME)
Definition member.hpp:340

This way the following use of one of those declarations won't require a hunt through the entire project to find where they came from by your successor after you're dead. Or by you next week.

◆ UGMISC_NAMED_MEMBER_STATIC_METHOD_CALL

#define UGMISC_NAMED_MEMBER_STATIC_METHOD_CALL ( TEMPLATENAME,
NAME )
Value:
UGMISC__DECL_MEMBER_CALLER_TYPE(TEMPLATENAME, NAME); \
template<class...T> class TEMPLATENAME \
: public ::ugmisc::member_::chain_caller< \
UGMISC__MEMBER_CALLER_TYPE_NAME(TEMPLATENAME), \
T... \
> \
{ \
static constexpr const char *template_name = #TEMPLATENAME; \
static constexpr const char *function_name = #NAME; \
}

Declares a template.

The template can be instantiated with a list of types. Then its static 'call' method, or the non-static operator() overload, can be called with any arguments, and will be forwarded to Type::NAME for the first type which accepts such a call.

For example:

using F = FooCall<X, Y, Z>;
struct no_foo_t {};
F::call(args...); // Error if X, Y, and Z don't have a static method called "foo".
F().call(args...); // Same as F::call(args...).
F()(args...); // Same as F::call(args...).

Default values

Continuing the above example:

F::fallback([] (){ return no_foo_t{}; })(args...);
F().fallback([] (){ return no_foo_t{}; })(args...); // Same as above.

If none of X, Y, and Z has a static method called "foo", the provided callable will be used instead. If forwarding args... to the callable is valid, that will be done. Otherwise the callable will be called without arguments.

See also
ugmisc::call_foo_method, for an example.

◆ UGMISC_NAMED_MEMBER_TYPE_TEST

#define UGMISC_NAMED_MEMBER_TYPE_TEST ( TEMPLATENAME,
ALIASNAME,
HASMEMBERNAME,
NAME )

Creates a type like this:

template<class T, class D=void>
struct TEMPLATENAME;

Which has members:

using type = ???; // The type T::NAME if it exists, otherwise D.
static constexpr bool has_member; // True if T::NAME exists.

Also creates the alias:

template<class T, class D=void> using ALIASNAME = typename TEMPLATENAME<T, D>::NAME;

and the template variable:

template<class T, class D=void>
static constexpr HASMEMBERNAME = TEMPLATENAME<T, D>::has_member;

T can be a ugmisc::type_list, which will check each type in order until if finds one with the named type member.

To pass a type which is actually be a ugmisc::type_list without giving it special treatment, wrap it in a ugmisc::wrapped_list. e.g.

wrapped_list<my_type_list>;
See also
UGMISC_MEMBER_TYPE_TEST