提供static_assert模板通常很有帮助.在模板不应该以某种方式实例化的情况下,我经常这样做
template<typename T, typename = void>
struct S
{
static_assert(false, "Unconditional error");
static_assert(sizeof(T) != sizeof(T), "Error on instantiation");
};
template<typename T>
struct S<T, std::enable_if_t<std::is_integral_v<T>>>
{
// ...
};
Run Code Online (Sandbox Code Playgroud)
static_assert即使没有实例化,第一个将立即失败S,而如果没有实例化将导致主模板,第二个将成功.
第二个static_assert显然是一个重言式,但它"取决于" T,以达到预期的效果.但这有保证吗?是否允许编译器评估这些重言式?
对于没有内置的C++版本,有两种广泛使用的静态断言实现static_assert.
第一个用于Boost并使用模板和该模板的特化:
template <bool> struct static_assert;
template <> struct static_assert<true> {}; // only true is defined
#define STATIC_ASSERT(x) static_assert<(x)>()
Run Code Online (Sandbox Code Playgroud)
这里一旦检查的条件为false,编译器就无法找到模板的通用版本,编译失败.
第二个使用typedef:
#define STATIC_ASSERT( x ) typedef char __STATIC_ASSERT__[( x )?1:-1]
Run Code Online (Sandbox Code Playgroud)
这里一旦违反了检查条件,编译器就会尝试typedef一个大小为-1的数组,这是非法的,因此是编译时错误.
对我来说后者更好,因为它保证不发出代码,也可以像这样使用(从这里):
template<int Shift> class BinaryFlag {
STATIC_ASSERT( 0 <= Shift && Shift < sizeof( DWORD) * CHAR_BIT );
public:
static const DWORD FlagValue = static_cast<DWORD>( 1 << Shift );
};
#define BINARY_FLAG( n ) CBinaryFlag<n>::FlagValue
Run Code Online (Sandbox Code Playgroud)
而前者不能那样使用.
有没有理由更喜欢静态断言的前一个实现而不是后者?
受这个问题的启发,我想知道是否有一些编译时检查可以引入检测两个给定的模板实例:
template <typename T>
class Templ...
typedef Templ<std::string> stringInstance;
typedef Templ<double> doubleInstance;
Run Code Online (Sandbox Code Playgroud)
是从相同的定义构造的,或者如果它们是从Templ模板的不同特化构建的
所以基本上假设的模板函数将表现如下:
template <typename T>
class Templ
{}
template <>
class Templ<std::string>
{}
template <>
class Templ<double>
{}
template <typename T1,typename T2>
class Belong_To_Same_Templ_Definition
{}
//tests
typedef Templ<std::string> stringInstance;
typedef Templ<double> doubleInstance;
typedef Templ<int> intInstance;
typedef Templ<char> charInstance;
assert( Belong_To_Same_Templ_Definition< intInstance , charInstance >::value == true);
assert( Belong_To_Same_Templ_Definition< intInstance , doubleInstance >::value == false);
assert( Belong_To_Same_Templ_Definition< stringInstance , doubleInstance >::value == false);
Run Code Online (Sandbox Code Playgroud)
有可能创造这种元功能吗?
c++ static-assert compile-time template-specialization template-meta-programming
鉴于以下内容
#include <array>
struct litmus final : std::array<unsigned char, 16>
{
};
static_assert(std::is_pod<std::array<unsigned char, 16> >::value, "not pod");
// this fails on MSVC:
static_assert(std::is_pod<litmus>::value, "not pod");
Run Code Online (Sandbox Code Playgroud)
以下编译器同意litmuspod:
但是,MSVC12(VS2013 RTM)认为第二个断言失败.
编辑有关信息:
is_trivially_copyable<litmus>在MSVC上返回true-ness.对于许多不严格要求实际POD的情况,这可能很有用.
为什么Visual Studio 2013编译器拒绝第一个静态断言(错误C2057),而不是第二个?
#include <limits>
typedef int Frequency;
const Frequency minHz{ 0 };
const Frequency maxHz{ std::numeric_limits<Frequency>::max() };
const Frequency invalidHz{ -1 };
static_assert(minHz < maxHz, "minHz must be less than maxHz"); // C2057
static_assert(invalidHz < minHz || invalidHz > maxHz, "invalidHz is valid"); // OK
Run Code Online (Sandbox Code Playgroud) static_assert在 的 false 分支中应丢弃以下内容if constexpr,但由于断言失败而导致编译失败:
#include <type_traits>
template <class T>
constexpr bool f() {
if constexpr (std::is_same<T, int>::value) return true;
else static_assert(false, "message");
}
int main () {
if constexpr (f<int>()) return 1;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我希望丢弃的分支if constexpr不会被评估,因为它f是用 type 实例化的int。
用 Gcc 7.2 (-std=c++17) 编译
我想用以下形式表达一个static_assert:
static_assert(expression should not compile);
Run Code Online (Sandbox Code Playgroud)
让我添加一个完整的示例:
template <bool Big>
struct A{};
template <>
struct A<true>
{
void a() {}
};
A<false> b;
static_assert(!compile(b.a()));
or
static_assert(!compile(A<false>::a()));
Run Code Online (Sandbox Code Playgroud)
因此,该想法是要确保不会编译表达式(具有有效语法)。
如果可能的话,该解决方案仅使用C ++ 11会更好。
假设我有以下定义:
#include <stdbool.h>
#include <stdint.h>
#define ASSERT(cond) _Static_assert(cond, #cond)
typedef union {
struct {
bool bit0:1;
bool bit1:1;
bool bit2:1;
bool bit3:1;
bool bit4:1;
bool bit5:1;
bool bit6:1;
bool bit7:1;
};
uint8_t bits;
} byte;
ASSERT(sizeof(byte) == sizeof(uint8_t));
Run Code Online (Sandbox Code Playgroud)
能不能写个代码,比如
#include <assert.h>
// ...
assert(((byte) { .bit0 = 1 }).bits == 0b00000001);
assert(((byte) { .bit1 = 1 }).bits == 0b00000010);
assert(((byte) { .bit2 = 1 }).bits == 0b00000100);
assert(((byte) { .bit3 = 1 }).bits == 0b00001000);
assert(((byte) { .bit4 = 1 …Run Code Online (Sandbox Code Playgroud) 我有这个 C++14 代码:
#include <type_traits>
struct f1 {
enum struct e { a };
};
struct f2 {
enum struct e {};
};
template <typename T>
struct my_struct {
using e = typename T::e;
my_struct()
: _e{e::a} {} // e::a used here
e _e;
};
int main() {
my_struct<f1> a;
my_struct<f2> b; // compilation fails
}
Run Code Online (Sandbox Code Playgroud)
显然,编译失败,类似于'a' is not a member of 'my_struct<f2>::e'. 我真的很想向 中添加一些静态断言my_struct,以添加自定义错误消息。首先,我可以检查是否e实际上是一个枚举:
static_assert(std::is_enum<e>::value, "my message");
Run Code Online (Sandbox Code Playgroud)
那么,我应该添加什么来静态断言e::a定义的?
我有一个事件处理程序类,它使用模板参数来设置事件类型。我想将这些事件类型强制为一字节大小的枚举类。针对大小的静态断言不是问题,但我无法在网上找到有关如何静态区分enum和enum class 的信息。
我现在的解决方案是使用C++ 前端实现语法扩展来断言枚举,然后断言正确的大小。在大多数平台上这是有效的,因为枚举使用int类型(通常大于一个字节)。
但这会导致稍微误导性的错误消息。我喜欢彻底。
我可以做哪些检查来传递类枚举,但会因常规的旧枚举而失败?
我不能使用type_traits,因为我使用的编译器(avr-gcc)不支持它。然而type_traits,当需要增加时,我会不断实施我自己的。因此,有关解决方案的任何提示type_traits仍然有用!
最小的例子:
// Event types
enum class tPass : uint8_t {};
enum class tFailSize : uint16_t {}; // Fail on size!
enum tFailType {}; // Currently fails on size, would like to fail on type!
// Event handler
template <typename TEvent>
class tEventHandler
{
static_assert(__is_enum(TEvent), "Must be class enum!"); // Doesn't really check for CLASS …Run Code Online (Sandbox Code Playgroud) static-assert ×10
c++ ×9
c++11 ×2
visual-c++ ×2
assertion ×1
bit-fields ×1
c ×1
c++14 ×1
compile-time ×1
constexpr ×1
enum-class ×1
enumeration ×1
enums ×1
gcc ×1
if-constexpr ×1
pod ×1
templates ×1