不幸的是,我的库的原始版本遗留了几个宏,这些宏使用了一些非常疯狂的 C。特别是,我有一系列宏,它们期望将某些类型传递给它们。是否可以按照以下方式做一些事情:
static_assert(decltype(retval) == bool);
如何?有没有聪明的选择?
是的,我知道宏很糟糕。我知道 C++ 不是 C 等等。
不幸的是,我的库的原始版本遗留了几个宏,这些宏使用了一些非常疯狂的 C。特别是,我有一系列宏,它们期望将某些类型传递给它们。是否可以按照以下方式做一些事情:
static_assert(decltype(retval) == bool);
如何?有没有聪明的选择?
是的,我知道宏很糟糕。我知道 C++ 不是 C 等等。
我发现这是最干净的,使用@UncleBens建议:
#include <type_traits>
static_assert(std::is_same<decltype(retval), bool>::value, "retval must be bool");
免责声明:这是一个糟糕的答案,肯定有更好的解决方案。只是一个例子:)
肯定已经实现了,但是自己实现却很琐碎;
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);
看来您需要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)
如果您确实关心const
andvolatile
限定符,并希望确保类型的const
andvolatile
部分也与您要比较的类型完全匹配,请像@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`");
如果您不关心const
OR 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 开始,您可以执行以下操作:
std::remove_cv_t<decltype(my_variable)>
代替std::remove_cv<decltype(my_variable)>::type
, 和:std::is_same_v<some_type, another_type>
代替std::is_same<some_type, another_type>::value
.std::remove_cv<>
, std::remove_const<>
,std::remove_volatile<>
static_assert
技巧的另一个答案]如何制作跨度大多数宏可以用inline
函数和/或模板替换。例如,过于聪明的参数大小检查 Posixisnan
宏是 C++0x 中的模板。哦,不好的例子,但你明白了。
该规则的主要例外是本质上实现高级语言功能的宏。例如,更智能的异常处理、协方差或一组参数化声明。
在某些情况下,不能合理地表示为inline
函数或模板的宏可以替换为更智能的预处理,即代码生成。然后你有一个脚本可以生成必要的代码。例如,可以使用宏和模板在纯 C++ 中创建选项类,但它很麻烦,并且作为一种更易于理解且可能更易于维护的替代方案,可以使用生成必需类的脚本,但代价是额外的构建步骤并处理多种语言。
干杯&hth.,