【问题标题】:Use static_assert to check types passed to macro使用 static_assert 检查传递给宏的类型
【发布时间】:2011-04-30 15:15:11
【问题描述】:

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

static_assert(decltype(retval) == bool);

怎么做?有什么聪明的替代品吗?

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

更新0

这里有一些related codesource file。欢迎提出建议。原来的问题保持不变。

【问题讨论】:

  • 看过实际的宏后,我强烈建议阅读 Modern C++ Design 或 [更多] Exceptional C++。
  • @MSalters:我无法想象 C++ 如何为我的进入/退出提供隐式替代方案,但我会看看。另请注意,写一个 FS 是非常 unmeta 的,我的目标不是创建一些宏大的 C++ 框架。
  • 你在入口处把一个对象放在栈上;范围的任何退出都会破坏对象。因此,进入时调用ctor,退出时调用dtor。自动 dtor 调用特别有用,我们从历史中知道,典型的程序员在函数的所有退出中会错过大约 5% 的宏。

标签: c++ c visual-studio-2010 g++ static-assert


【解决方案1】:

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

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

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

【讨论】:

  • 虽然我不理解 AssertHasType 和以下几行的语法,但答案/概念一点也不差。不过,我建议制作元函数和静态断言实用程序,它提供了两个可重用的实用程序,它们可以组合起来产生预期的效果,而不是根据条件进行自定义检查。
  • 或者使用type_traits标头中的is_same(我希望VC10可以使用)。
【解决方案2】:

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

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

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

干杯,

【讨论】:

  • 请在您投反对票时提供理由。这有助于其他人理解答案有什么问题。或者,它可以帮助其他人无视反对票。
  • +1。看过代码后,很明显实际的宏被一个堆栈分配的对象简单地替换了,大大提高了可靠性和可读性。这些宏用于函数调用/返回日志记录。
【解决方案3】:

看来您需要decltype,因为您有一个表达式,但想要验证一个类型。现在已经有足够的方法来做到这一点(C++03)。例如,检查一个布尔值

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)

【讨论】:

  • 为了提升级别的健壮性,你需要一个address_of 模板来捕获那些重载了一元T::operator&amp;()的白痴
【解决方案4】:

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

#include <type_traits>

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

【讨论】:

  • 什么是 c++03 等价物?
  • @balki:只需升级到 C++11。 C++ 已经够糟糕的了,不要让自己变得更糟 :)
  • 使用std::is_same时,一定要#include &lt;type_traits&gt;
  • const / 引用限定符呢?
  • @einpoklum-reinstateMonica 你可以使用std::remove_conststd::remove_reference等。C++20也有std::remove_cvref
【解决方案5】:

如果您确实关心constvolatile 限定符,并希望确保类型的constvolatile 部分也与您要比较的类型完全匹配,请执行like @Matt Joiner says:

#include <type_traits>

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

但是,我不关心const,并且只想确保类型是特定类型而不考虑const,请改为执行以下操作。注意这里需要std::remove_const&lt;&gt;::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 也是如此。如果您也不关心类型的volatile 部分,可以使用std::remove_volatile&lt;&gt;::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&lt;&gt;::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&lt;decltype(my_variable)&gt; 代替 std::remove_cv&lt;decltype(my_variable)&gt;::type,并且:
  2. std::is_same_v&lt;some_type, another_type&gt; 代替 std::is_same&lt;some_type, another_type&gt;::value

参考资料:

  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&lt;&gt;, std::remove_const&lt;&gt;, std::remove_volatile&lt;&gt;

相关:

  1. [我使用上述static_assert技巧的另一个答案]How to make span of spans
  2. Static assert in C[我自己的回答]
  3. How to use static assert in C to check the types of parameters passed to a macro [我自己的问题]
  4. Typechecking macro arguments in C
  5. *****C++ Limit template type to numbers

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-30
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 2020-05-26
    相关资源
    最近更新 更多