Use static_assert to check types passed to macro
I found this to be the cleanest, using @UncleBens suggestion:
#include <type_traits>
static_assert(std::is_same<decltype(retval), bool>::value, "retval must be bool");
Determine if same pointers are passed to a macro
So you want to check if same name is passed to both arguments, right? Then this simple trick works
#define ASSERT_IF_NULL_2(_ptr1, _ptr2)\
{\
int _check_##_ptr1;\
int _check_##_ptr2;\
}\
ASSERT(_ptr1);\
ASSERT(_ptr2);
int main ()
{
int* ptr1;
int* ptr2;
ASSERT_IF_NULL_2 (ptr1, ptr1); // error: redeclaration of `int _check_ptr1'
ASSERT_IF_NULL_2 (ptr1, ptr2); // OK
}
EDIT (By OP, Ajay):
On Visual C++ compiler, we can use MS specific keyword __if_exists
to give error through static-assert
:
#define ASSERT_IF_NULL_2(_ptr1, _ptr2)\
{\
int _check_##_ptr1;\
__if_exists(_check_##_ptr2)
STATIC_ASSERT(false, "Same pointer passed twice")
}\
Since static_assert
keyword doesnt exist for pre-VS2010 compilers, one may use custom-written STATIC_ASSERT.
How to do static_assert with macros?
Prior to C++11 I would normally do:
typedef int static_assert_something[something ? 1 : -1];
You can also look at boost static assert. But it is too bloated for my liking. It is easy to make things bigger, it is hard to make them any better.
static_assert in a macro but also expand to something that can be used as a function parameter
You should be using std::extent
instead of that macro, which gives you 0 for unsupported types (e.g. arrays without bounds, non-array types).
For your use case a constexpr function that gives you the size for an array variable would be better suited, like so:
template <typename T, std::size_t N>
constexpr std::size_t arrsize(T (&)[N]) {
return N;
}
Then you don't need to assert on the size since you can only use the function with actual arrays.
Static Assert to check compile-time-constant is NOT passed to macro
You could redefine the macro so that it takes the address of the parameter - that should fail for literals. However that will not prevent you from passing a constant variable, e.g.
const static int FIVE = 5;
ASSERT_FOR_DEFAULT(FIVE); // still works.
To prohibit all kinds of constants from being passed to your macro call a function that takes the parameter by non-const reference:
template <class T> void noConstAllowed(T&){};
#define ASSERT_FOR_DEFAULT_VALUE(val) \
{ \
(void*)&(val); /* no literals*/ \
noConstAllowed(val); /* no constants at all */ \
switchHitDefaultDialog(val, __FILE__, __LINE__); \
}
I suppose you use something like FILE or other positional macros or you would have made it a function. Of yourse, you only need to use one of the two lines.
Static assert in C
C11 standard adds the _Static_assert
keyword.
This is implemented since gcc-4.6:
_Static_assert (0, "assert1"); /* { dg-error "static assertion failed: \"assert1\"" } */
The first slot needs to be an integral constant expression. The second slot is a constant string literal which can be long (_Static_assert(0, L"assertion of doom!")
).
I should note that this is also implemented in recent versions of clang.
Verify macro argument size at compilation time
The type of the ternary ?:
expression is the common type of its second and third arguments (with integer promotion of smaller types). So the following version of your MY_MACRO
will work in a 32-bit architecture:
static_assert(sizeof(uint32_t) == sizeof 0, ""); // sanity check, for your machine
#define MY_MACRO(arg0, arg1, arg2) \
do { \
static_assert(sizeof(0 ? 0 : (arg0)) == sizeof 0, ""); \
static_assert(sizeof(0 ? 0 : (arg1)) == sizeof 0, ""); \
static_assert(sizeof(0 ? 0 : (arg2)) == sizeof 0, ""); \
my_macro_impl((uint32_t)(arg0), (uint32_t)(arg1), (uint32_t)(arg2)); \
} while (0)
Moreover, this solution should work with all versions of C and C++ (with, if necessary, a suitable definition of static_assert
).
Note this macro, like the OP's original, has function semantics in that the arguments are evaluated only once, unlike for example the notorious MAX
macro.
Related Topics
Good C++ Array Class for Dealing with Large Arrays of Data in a Fast and Memory Efficient Way
C++ Is It Necessary to Delete Dynamically Allocated Objects at the End of the Main Scope
What's the Difference Between Cout<<Cout and Cout<<&Cout in C++
For-Loop in C++ Using Double Breaking Out One Step Early, Boundary Value Not Reached
How to Make Camera Follow a 3D Object in Opengl
What Does the C++ New Operator Do Other Than Allocation and a Ctor Call
How to Find an Object with Specific Field Values in a Std::Set
Interactive Console Programming for C/C++
Addresses of Identical Function Template Instantiations Across Compilation Units
Access Child Members Within Parent Class, C++
Factor a Large Number Efficiently with Gmp
Msvc Equivalent of _Attribute_ ((Warn_Unused_Result))
Cmake: How to Change Properties on Subdirectory Project Targets
Rvalue Reference Parameters and Template Functions