Is there a __CLASS__ macro in C++?
The closest thing there's is to call typeid(your_class).name()
- but this produces compiler specific mangled name.
To use it inside class just typeid(*this).name()
Is there C macro for member methods?
Yes, it is possible if you're able to use the variadic macros feature:
// ...
#define CALL_METHOD(x, y, ...) x->y(x, ##__VA_ARGS__)
struct string
{
char *value;
size_t (*size)(struct string *);
int (*compare)(struct string *, struct string *);
int (*set_value)(struct string *, const char *);
};
// ...
int main()
{
// ...
CALL_METHOD(s1, set_value, "foo");
CALL_METHOD(s2, set_value, "bar");
printf("s1->size(s1) = %zu;\n", s1->size(s1));
printf("CALL_METHOD(s1, size) = %zu;\n", CALL_METHOD(s1, size));
printf("s1->compare(s1, s2) = %d;\n", s1->compare(s1, s2));
printf("CALL_METHOD(s1, compare, s2) = %d;\n", CALL_METHOD(s1, compare, s2));
// ...
}
What is the meaning of macro in front of class definition in c++
It's not standard C++ (unless the macro evaluates to whitespace, or you're using attributes) but it's required by some compilers when targeting certain platforms.
A common occurrence is when building a dynamic linked library (dll) for Windows. OCTINTERP_API
is likely set to __declspec(dllexport)
when building the dll, and __declspec(dllimport)
when using the dll.
(See https://en.cppreference.com/w/cpp/language/classes)
Declare a class and member variables using macros in C++
#define NEW_CLASS(name_, seq_) \
class name_ : public ClassBase \
{ \
public: \
IMPL_NEW_CLASS_end(IMPL_NEW_CLASS_decl_loop_a seq_)\
\
std::vector<void *> fun() \
{ \
return { IMPL_NEW_CLASS_end(IMPL_NEW_CLASS_list_loop_a seq_) }; \
} \
};
#define IMPL_NEW_CLASS_end(...) IMPL_NEW_CLASS_end_(__VA_ARGS__)
#define IMPL_NEW_CLASS_end_(...) __VA_ARGS__##_end
#define IMPL_NEW_CLASS_decl_loop_a(...) ::std::type_identity_t<__VA_ARGS__> IMPL_NEW_CLASS_decl_loop_b
#define IMPL_NEW_CLASS_decl_loop_b(name_) name_; IMPL_NEW_CLASS_decl_loop_a
#define IMPL_NEW_CLASS_decl_loop_a_end
#define IMPL_NEW_CLASS_list_loop_a(...) IMPL_NEW_CLASS_list_loop_b
#define IMPL_NEW_CLASS_list_loop_b(name_) &name_, IMPL_NEW_CLASS_list_loop_a
#define IMPL_NEW_CLASS_list_loop_a_end
NEW_CLASS(ClassA, (int)(a) (float)(b) (char)(c))
I've used the (a)(b)(c)
syntax for lists, because AFAIK only those lists can be traversed without generating a bunch of repetitive boilerplate macros. (can't do that with a, b, c
)
I've wrapped the type in std::type_identity_t<...>
to allow arrays, function pointers, etc (int[4] x;
is invalid, but std::type_identity_t<int[4]> x;
is ok).
I chose this specific syntax because the types can contain commas, so e.g. (type,name)(type,name)
wouldn't be viable, because it's tricky to extract the last element from a comma-separated list (consider (std::map<int,float>,x)
, which counts as a comma-separated list with 3 elements).
(name,type)(name,type)
, on the other hand, would be viable (extracting the first element of a list is simple), but it doesn't look as good. If you go for this syntax, note that the loops still have to use at least two macros each (_a
and _b
in my example), even if the two would be the same (a single-macro loop doesn't work because of the ban on recursive macros). The loops would also need two _end
macros each, not one.
With C++17 only, Is it possible to create a macro which accepts class and method name and returns true if such a method exists in the class?
Yes, this is possible, though it does require a macro AFAIK, but you seem to not mind that.
We of course need some SFINAE context because that is the only place where we are allowed to write syntax errors. But creating in-place templates is tricky because local classes cannot contain them, so even if(class { /* template magic */}x; <something with x>)
C++17 feature won't help much.
Since C++14 there is one feature that I am aware of which does allow defining types with templated methods inside an expression - templated lambdas.
I took inspiration from std::visit
with overloaded set and SFINAE test using overloads:
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
// explicit deduction guide (not needed as of C++20)
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
#define HAS_METHOD(class_type,method) \
overloaded { \
[](auto* arg, decltype(&std::decay_t<decltype(*arg)>::method) ptr) constexpr \
{ return true;}, \
[](auto* arg, ...) constexpr \
{ return false;} \
}((class_type*)nullptr,nullptr)
#include <iostream>
int main()
{
struct S{void call();};
if constexpr (HAS_METHOD(S,call))
std::cout << "S has a call\n";
else
std::cout << "S does not have a call\n";
if constexpr (HAS_METHOD(S,call2))
std::cout << "S has a call2\n";
else
std::cout << "S does not have a call2\n";
}
Output(Godbolt):
S has a call
S does not have a call2
Explanation
Overload-based SFINAE
Based on this answer, one can base SFINAE on overloading resolution between templated functions. Nice property of this is there is no need for specialization.
Here I used this approach for lambda's templated operator()
. The code boils down to something like this:
struct overload{
template<class T>
bool operator()(T * arg, decltype(&std::decay_t<decltype(*arg)>::call) ptr)
{
return true;
}
template<class T>
bool operator()(T * arg, ...)
{
return false;
}
};
When we call overload{...}((S*)nullptr,nullptr)
, T
is deduced to be S
from the first parameter. This effectivelly gets rids of the templated code while still being in SFINAE context. The first (auxillary) parameter is necessary because lambdas do not have template <typename S>
prior to C++20, also to obtain the type, one has to use decltype(arg)
. std::decay_t
is required because dereferencing a pointer returns a reference and T&::call
is never valid syntax.
Note that one cannot use std::declval
here because the context is evaluated. Pointer it is then, we won't actually dereference it anywhere. Now
- If
S::call
is valid, the second parameter is of type "pointer to a member function withcall
's signature". Of coursenullptr
is a valid value for any pointer. Because this overload is more specific than...
(anything valid is), it is chosen andtrue
is returned inconstexpr
manner. - If
S::call
constitues a syntax error, the first overload is discarded by SFINAE, the second still matches because...
will matchnullptr
and the first argument could still be deduced. In that case we returnfalse
.
Overloading
To build the required set of overloads from lambdas in one expression, one can use parameter pack expansion and inheritance of methods which is exactly what this line from std::visit
helper does:
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
Then the macro itself just construct a temporary instance of this class, ctor is used to initialize the base classes = pass the lambdas. After that, the temporary is immedietely called with ((S*)nullptr,nullptr)
arguments.
Refer to class in C++ macro
This is closely related this question. The answer is that you can not (yet) write something that uses the type of the class definition you are in. You will have to write a macro that includes the start of the class definition (i.e the struct Foo)
and some mechanism to facilitate the typedef.
Class name macro
Use a macro to define the class:
#define CLASS_WITH_NAME(name) name { const char * __NAME = #name;
class CLASS_WITH_NAME(class_name) // No "{" here!
Ugly hack but the best I can think of.
macro in front of class definition in c++
Checking OpenRTI's source code, it looks like it is simply indicating that the simply is meant to be hidden when compiled as a shared library:
// Now we use the generic helper definitions above to define OPENRTI_API and OPENRTI_LOCAL.
// OPENRTI_LOCAL is used for non-api symbols.
#ifdef OPENRTI_DLL // defined if OPENRTI is compiled as a DLL
# define OPENRTI_LOCAL OPENRTI_HELPER_DLL_LOCAL
#else // OPENRTI_DLL is not defined: this means OPENRTI is a static lib.
# define OPENRTI_LOCAL
#endif // OPENRTI_DLL
And OPENRTI_HELPER_DLL_LOCAL
is:
// Generic helper definitions for shared library support
#if defined _WIN32 || defined __CYGWIN__
# define OPENRTI_HELPER_DLL_LOCAL
#elif defined __GNUC__ && (4 <= __GNUC__)
# define OPENRTI_HELPER_DLL_LOCAL __attribute__ ((visibility("hidden")))
#elif defined __SUNPRO_C && (0x550 <= __SUNPRO_C)
# define OPENRTI_HELPER_DLL_LOCAL __hidden
#else
# define OPENRTI_HELPER_DLL_LOCAL
#endif
Related Topics
How to Set Up Google C++ Testing Framework (Gtest) With Visual Studio 2005
Why Is 'This' a Pointer and Not a Reference
C/C++ Check If One Bit Is Set In, I.E. Int Variable
What Are the Pointer-To-Member Operators -≫* and .* in C++
Why Can't I Have a Non-Integral Static Const Member in a Class
Linux: Executing Child Process With Piped Stdin/Stdout
Std::Thread Pass by Reference Calls Copy Constructor
Nice Way to Append a Vector to Itself
Metaprograming: Failure of Function Definition Defines a Separate Function
C++ Preprocessor #Define-Ing a Keyword. Is It Standards Conforming
Why Is the Destructor of a Future Returned from 'Std::Async' Blocking
How to Print Utf-8 from C++ Console Application on Windows
How to Detect Win32 Process Creation/Termination in C++
Initialize a Const Array in a Class Initializer in C++