问题
I unfortunately have several macros left over from the original version of my library that employed some pretty crazy C. In particular, I have a series of macros that expect certain types to be passed to them. Is it possible to do something along the lines of:
static_assert(decltype(retval) == bool);
And how? Are there any clever alternatives?
Yes I'm aware macros are bad. I'm aware C++ is not C, etc.
Update0
Here is some related code, and the source file. Suggestions are welcome. The original question remains the same.
回答1:
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");
回答2:
It appears you need decltype
because you've got an expression, but want to verify a type. There are already enough ways to do that now (C++03). For instance, to check a bool
inline void mustBeBool(bool) { }
template<typename T> inline void mustBeBool(T t) { & (&t); } // Takes address of rvalue (&t)
// Use:
#define DifficultMacro(B) do { mustBeBool(B); foo(B); } while (false)
回答3:
Disclaimer: This is a bad answer, there are definitely far better solutions. Just an example :)
It is bound to be already implemented, but it's trivial to implement yourself;
template <class T1, class T2> struct CheckSameType; //no definition
template <class T> struct CheckSameType<T,T>{}; //
template <class T1, class T2>
AssertHasType(T2)
{
CheckSameType<T1, T2> tmp; //will result in error if T1 is not T2
}
To be used like this:
AssertHasType<bool>(retval);
Alternative (suggested by GMan):
template <class T1, class T2> struct SameType
{
enum{value = false};
}
template <class T> struct SameType<T,T>
{
enum{value = true};
};
To be used like
static_assert(SameType<decltype(retval), bool>::value);
回答4:
Most macros can be replaced with inline
functions and/or templates. As a case in point, the overly clever argument-size-checking Posix isnan
macro is a template in C++0x. Oh,bad example, but you get the idea.
The main exceptions to that rule are macros that essentially implement higher level language features. For example, smarter exception handling, or covariance, or a parameterized set of declarations.
In some cases the macros that can't be reasonable expressed as inline
functions or templates, can be replaced with a smarter kind of preprocessing, namely code generation. Then you have a script somewhere that generates the necessary code. For example, it's possible to do options classes in pure C++ with macros and templates, but it's hairy, and as an easier-to-grok and perhaps more maintainable alternative one might use a script that generates the requisite classes, at the cost of extra build steps and dealing with multiple languages.
Cheers & hth.,
回答5:
If you DO care about the const
and volatile
qualifiers, and want to ensure the const
and volatile
parts of the types also exactly match the type you are comparing against, do like @Matt Joiner says:
#include <type_traits>
static_assert(std::is_same<decltype(my_variable), uint64_t>::value,
"type must be `uint64_t`");
I you do NOT care about const
, however, and want to simply ensure the type is a certain type without regard for const
, do the following instead. Note that std::remove_const<>::type
is required here:
static_assert(std::is_same<std::remove_const<decltype(my_variable)>::type, uint64_t>::value,
"type must be `uint64_t` OR `const uint64_t`");
The same goes for volatile
. In case you don't care about the volatile
part of the type either, you can ignore it with std::remove_volatile<>::type
:
static_assert(std::is_same<std::remove_volatile<decltype(my_variable)>::type, uint64_t>::value,
"type must be `uint64_t` OR `volatile uint64_t`");
If you don't care about const
OR volatile
, you can remove them both with std::remove_cv<>::type
:
static_assert(std::is_same<std::remove_cv<decltype(my_variable)>::type, uint64_t>::value,
"type must be `uint64_t` OR `const uint64_t` OR `volatile uint64_t` OR `volatile const uint64_t`");
References:
- Use static_assert to check types passed to macro
- https://en.cppreference.com/w/cpp/types/is_same
- https://en.cppreference.com/w/cpp/language/decltype
- https://en.cppreference.com/w/cpp/header/type_traits
- https://en.cppreference.com/w/cpp/types/remove_cv -
std::remove_cv<>
,std::remove_const<>
,std::remove_volatile<>
Related:
- Static assert in C [my own answer]
- How to use static assert in C to check the types of parameters passed to a macro [my own question]
- Typechecking macro arguments in C
来源:https://stackoverflow.com/questions/4021981/use-static-assert-to-check-types-passed-to-macro