32

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

static_assert(decltype(retval) == bool);

如何?有没有聪明的选择?

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

更新0

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

4

5 回答 5

63

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

#include <type_traits>

static_assert(std::is_same<decltype(retval), bool>::value, "retval must be bool");
于 2010-10-27T01:27:15.807 回答
3

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

肯定已经实现了,但是自己实现却很琐碎;

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);
于 2010-10-26T08:48:20.513 回答
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)
于 2010-10-26T14:01:28.560 回答
3

如果您确实关心constandvolatile限定符,并希望确保类型的constandvolatile部分也与您要比较的类型完全匹配,请像@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。如果您也不关心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`");

如果您不关心constOR volatile,则可以使用以下命令将它们都删除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<decltype(my_variable)>代替std::remove_cv<decltype(my_variable)>::type, 和:
  2. std::is_same_v<some_type, another_type>代替std::is_same<some_type, another_type>::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_const<>,std::remove_volatile<>

有关的:

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

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

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

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

干杯&hth.,

于 2010-10-26T09:01:27.437 回答