使用 static_assert 检查传递给宏的类型

发布于 2024-09-28 21:48:29 字数 465 浏览 7 评论 0原文

不幸的是,我的库的原始版本留下了几个宏,这些宏使用了一些非常疯狂的 C。特别是,我有一系列宏,它们期望将某些类型传递给它们。 是否可以按照以下方式做一些事情:

static_assert(decltype(retval) == bool);

以及如何做?有什么聪明的替代方案吗?

是的,我知道宏很糟糕。我知道 C++ 不是 C 等。

Update0

这里有一些 相关代码,以及 源文件。欢迎提出建议。原来的问题保持不变。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

花开浅夏 2024-10-05 21:48:29

我发现这是最干净的,使用 @UncleBens 建议:

#include <type_traits>

static_assert(std::is_same<decltype(retval), bool>::value, "retval must be bool");

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");
捶死心动 2024-10-05 21:48:29

如果您确实关心 const易失性 限定符,并且希望确保类型也与您要比较的类型完全匹配,就像@Matt Joiner所说

#include <type_traits>

static_assert(std::is_same<decltype(my_variable), uint64_t>::value, 
              "type must be `uint64_t`"); 

我你不关心const,但是,如果想要简单地确保类型是某种类型而不考虑 const,请改为执行以下操作。请注意,这里需要 std::remove_const<>::type

static_assert(std::is_same<std::remove_const<decltype(my_variable)>::type, uint64_t>::value, 
              "type must be `uint64_t` OR `const uint64_t`");   

volatile 也是如此。如果您也不关心类型的 易失性 部分,则可以使用 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`");

如果您不这样做不关心 constvolatile,您可以使用 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`");

另请注意,截至C++17 你可以这样做:

  1. std::remove_cv_t 代替 std::remove_cv::type ,并且:用
  2. std::is_same_v 代替 std::is_same::value

参考文献:

  1. 使用 static_assert 检查传递给宏的类型
  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_conststd::remove_volatile<>< /code>

相关:

  1. [我使用上述 static_assert 技巧的另一个答案] 如何制作跨度
  2. 静态在 C 中断言 [我自己的答案]
  3. 如何在 C 中使用静态断言来检查传递给宏的参数类型 [我自己的问题]
  4. 在 C 中对宏参数进行类型检查
  5. *****C++ 将模板类型限制为数字

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`");

Note also that as of C++17 you can do:

  1. std::remove_cv_t<decltype(my_variable)> in place of std::remove_cv<decltype(my_variable)>::type, and:
  2. std::is_same_v<some_type, another_type> in place of std::is_same<some_type, another_type>::value.

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. [another answer of mine where I use the above static_assert tricks] How to make span of spans
  2. Static assert in C [my own answer]
  3. How to use static assert in C to check the types of parameters passed to a macro [my own question]
  4. Typechecking macro arguments in C
  5. *****C++ Limit template type to numbers
天生の放荡 2024-10-05 21:48:29

免责声明:这是一个糟糕的答案,肯定有更好的解决方案。只是一个例子:)

它肯定已经实现了,但是自己实现是微不足道的;

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
}

像这样使用:

AssertHasType<bool>(retval);

替代(GMan 建议):

template <class T1, class T2> struct SameType
{
    enum{value = false};
}
template <class T> struct SameType<T,T>
{
    enum{value = true};
}; 

static_assert(SameType<decltype(retval), bool>::value);

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);
阳光①夏 2024-10-05 21:48:29

看来您需要 decltype 因为您有一个表达式,但想要验证类型。现在已经有足够的方法可以做到这一点(C++03)。例如,要检查 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)

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)
夜深人未静 2024-10-05 21:48:29

大多数宏都可以替换为内联函数和/或模板。作为一个恰当的例子,过于聪明的参数大小检查 Posix isnan 宏是 C++0x 中的一个模板。哦,例子不好,但你明白了。

该规则的主要例外是本质上实现更高级别语言功能的宏。例如,更智能的异常处理、协方差或参数化声明集。

在某些情况下,无法合理表示为内联函数或模板的宏可以用更智能的预处理(即代码生成)来替换。然后你在某个地方有一个脚本可以生成必要的代码。例如,可以使用宏和模板在纯 C++ 中创建选项类,但它很麻烦,并且作为一种更容易理解并且可能更易于维护的替代方案,可以使用生成必需类的脚本,但需要额外的成本构建步骤并处理多种语言。

干杯&呵呵,,

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.,

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文