静态断言非常便于在编译时检查事物.一个简单的静态断言习惯用法如下:
template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};
#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0)
Run Code Online (Sandbox Code Playgroud)
这对于像这样的东西很有用
STATIC_ASSERT(sizeof(float) == 4)
Run Code Online (Sandbox Code Playgroud)
和:
#define THIS_LIMIT (1000)
...
STATIC_ASSERT(THIS_LIMIT > OTHER_LIMIT);
Run Code Online (Sandbox Code Playgroud)
但是使用#define不是定义常量的"C++"方式.C++会让你使用匿名命名空间:
namespace {
const int THIS_LIMIT = 1000;
}
Run Code Online (Sandbox Code Playgroud)
甚至:
static const int THIS_LIMIT = 1000;
Run Code Online (Sandbox Code Playgroud)
这样做的问题在于,const int你不能使用STATIC_ASSERT(),你必须采用愚蠢的运行时检查.
有没有办法在当前的C++中正确解决这个问题?
我想我已经读过C++ 0x有一些工具可以做到这一点......
编辑
好的,这个
static const int THIS_LIMIT = 1000;
...
STATIC_ASSERT(THIS_LIMIT > 0);
Run Code Online (Sandbox Code Playgroud)
编译好
但是这个:
static const float THIS_LIMIT = 1000.0f;
...
STATIC_ASSERT(THIS_LIMIT > 0.0f);
Run Code Online (Sandbox Code Playgroud)
才不是.
(在Visual …
假设我有这些类型:
struct A {
int a;
};
struct B {
int b;
};
struct C : public A, public B {
int c;
};
Run Code Online (Sandbox Code Playgroud)
一个C*指针可以被转换为A*指针,而完全不调整的实际地址.但是当C*被投射时B*,价值必须改变.我想确保我所拥有的两个相关类型可以在不改变地址的情况下相互转换(即没有多重继承,或者基类是派生类的第一个基础).这可以在运行时检查,例如像这样
assert(size_t(static_cast<A*>((C*)0xF000) == 0xF000);
assert(size_t(static_cast<B*>((C*)0xF000) != 0xF000);
Run Code Online (Sandbox Code Playgroud)
这样可行.但是这个信息在编译时是已知的,所以我正在寻找一种方法来对它进行编译时断言.将上面的内容转换为静态断言的明显方法(例如assert,BOOST_STATIC_ASSERT使用g ++ 4.2 将替换为错误的"强制转换为除积分或枚举类型以外的类型"不能出现在常量表达式中).
便携性不是很重要.使用gcc扩展或hacky模板技巧都可以.
更新:发现以前几乎同样的问题:C++,静态检测具有不同地址的基类?.使用offsetof()也是唯一有用的建议.
为什么constexpr变量的decltype失败?
#include <cstdint>
#include <type_traits>
constexpr uint16_t foo(){ return 0;}
constexpr auto cv = foo();
auto v = foo();
static_assert( std::is_same< uint16_t, decltype(cv)>::value, "!"); // failed
static_assert( std::is_same< uint16_t, decltype(v) >::value, "!"); // success
Run Code Online (Sandbox Code Playgroud) 问题
不构建以下内容,因为该消息不是字符串文字.
template<typename T>
struct Foo
{
Foo()
{
static_assert( is_pod<T>::value, typeid(T).name() );
}
};
Run Code Online (Sandbox Code Playgroud)
最终,如果我尝试编译,我想要一个失败的消息,如"Bar必须是pod-type" Foo<Bar> fb;.
是否可以在编译期间构建此字符串,如static_assert?
考虑一个功能
void f() {
assert(condition);
...
}
Run Code Online (Sandbox Code Playgroud)
在调试模式下,如果启用了断言,则编译器可以自由地假设condition保持,因为如果没有,则不会执行剩余的代码.
但是,在发布模式下,我相信编译器只会看到
void f() {
...
}
Run Code Online (Sandbox Code Playgroud)
而且不能再假设了condition.
是否有任何编译器指令或静态断言技巧让编译器了解某些不变量?
我想在实例化时检查以下结构的大小,static_assert以约束未命名struct的紧密包装,因此大小A相当于sizeof(T) * 3.
template <typename T>
struct A
{
union
{
struct { T a, b, c; };
T arr[3];
};
};
Run Code Online (Sandbox Code Playgroud)
这可以用
static_assert(sizeof(A<T>) == sizeof(T) * 3, "hey something went wrong");
Run Code Online (Sandbox Code Playgroud)
然而
因为A<T>在其类定义中仍然是一个不完整的类型,所以将上述内容static_assert放入类定义中是不可取的
static_assertwith sizeof不评估所有编译器(如Clang)中未实例化的函数内部,因此将其放入虚拟成员函数不是一种选择
放入static_assert构造函数或析构函数将是一个解决方案,但在上面的示例中不存在用户定义的构造函数(考虑聚合),进一步想象多个构造函数的情况,我将避免在所有构造函数中执行断言
继承A自另一个结构,并static_assert在定义中执行A将是一个解决方案,但我想保持结构简单,而不会搞乱辅助结构
我失踪的任何其他解决方案?
我决定取消删除这个问题,并在将来为可能的解决方案保持开放.
请考虑以下代码:
template<typename Derived>
struct Base {
static constexpr int x_base = Derived::x_derived;
//static_assert(x_base > 1, "Oops");
};
struct Derived : public Base<Derived> {
static constexpr int x_derived = 5 ;
};
Base<Derived> obj;
Run Code Online (Sandbox Code Playgroud)
这在gcc上编译很好,但如果我取消注释该static_assert行,它会抱怨
error: incomplete type 'Derived' used in nested name specifier
static constexpr int x_base = Derived::x_derived;
Run Code Online (Sandbox Code Playgroud)
我从4.9到5.3的不同版本的gcc试了一下,我也得到了同样的错误(你可以尝试在godbolt 这里).即使没有static_assert,clang也拒绝编译它,并抱怨
error: no member named 'x_derived' in 'Derived'
static constexpr int x_base = Derived::x_derived;
Run Code Online (Sandbox Code Playgroud)
哪个编译器是正确的(如果有的话)?有没有一种很好的方法来修复代码?
如何解决这个问题:
我有预定义的整数常量列表:
const auto numbers = {1, 5, 10};
Run Code Online (Sandbox Code Playgroud)
我想使用static_assert(编译时)来检查是否有其他一些const值:
#define SOME_IDENTIFIER 1
Run Code Online (Sandbox Code Playgroud)
在列表中.你会怎么做?可能吗?谢谢!
我昨天读了几个关于在an 子句中使用的答案。我知道根据标准,它被认为是格式错误的(即使某些编译器,包括 MSVC2017,会接受它)。Qt 也会将此标记为错误。static_assert(false, "Some message")elseif constexpr
我的问题是,下面的代码是否符合标准?(我倾向于这么认为,但我想确认一下。)
template <typename TypeOfValue>
static void PushValue(duk_context* ctx, TypeOfValue value) {
// Push value onto duktape stack
if constexpr (std::is_same<TypeOfValue, int>::value) {
// Push int
duk_push_int(ctx, value);
} else if constexpr (std::is_same<TypeOfValue, uint32_t>::value) {
// Push uint
duk_push_uint(ctx, value);
} else {
// Unsupported type
static_assert(bool_value<false, TypeOfValue>(), "Unsupported type");
}
}
template <bool value, typename T>
static constexpr bool bool_value() {return value;}
Run Code Online (Sandbox Code Playgroud)
编辑: …
我试图static_assert通过比较静态字段上的指针来验证程序是否真的有两个从模板生成的不同类。经过一些简化后,程序如下所示:
template<int N> struct C {
static int x;
};
template<int N> int C<N>::x = 0;
int main() {
static_assert(&C<0>::x != &C<1>::x);
}
Run Code Online (Sandbox Code Playgroud)
Clang 没问题,但 GCC 打印错误:
error: non-constant condition for static assertion
Run Code Online (Sandbox Code Playgroud)
演示:https : //gcc.godbolt.org/z/o6dE3GaMK
我想知道在编译时是否真的允许进行这种类型的检查?