Use static_assert to check types passed to macro

拜拜、爱过 提交于 2020-04-05 11:50:26

问题


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:

  1. Use static_assert to check types passed to macro
  2. https://en.cppreference.com/w/cpp/types/is_same
  3. https://en.cppreference.com/w/cpp/language/decltype
  4. https://en.cppreference.com/w/cpp/header/type_traits
  5. https://en.cppreference.com/w/cpp/types/remove_cv - std::remove_cv<>, std::remove_const<>, std::remove_volatile<>

Related:

  1. Static assert in C [my own answer]
  2. How to use static assert in C to check the types of parameters passed to a macro [my own question]
  3. Typechecking macro arguments in C


来源:https://stackoverflow.com/questions/4021981/use-static-assert-to-check-types-passed-to-macro

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!