在编译时以 static_assert() 格式显示整数
Display integer at compile time in static_assert()
这是我正在尝试做的事情的简化版本
enum First
{
a,
b,
c,
nbElementFirstEnum,
};
enum Second
{
a,
b,
c,
nbElementSecondEnum,
};
static_assert(
First::nbElementFirstEnum == Second::nbElementSecondEnum,
"Not the same number of element in the enums.");
/*static_assert(
First::nbElementFirstEnum == Second::nbElementSecondEnum,
"Not the same number of element in the enums." + First::nbElementFirstEnum + " " + Second::nbElementSecondEnum);*/
但是我希望能够在断言消息中打印First::nbElementFirstEnum和Second::nbElementSecondEnum的值(就像在注释版本中显然不起作用一样)。我尝试使用带有"#"的宏连接。我还尝试使用可变参数模板,检索每个数字 %10 并将"0"字符添加到检索到的值中,但我得到的只是一个 constexpr char[]。
所以我的问题是我怎样才能让我的枚举值打印在字符串文字中。
可能的重复项:
C++11 static_assert:参数化错误消息
在输出中集成类型名称static_assert?
最有趣的话题是这个:编译时的打印大小(T)但我不想有警告,或取消注释代码以了解值。
首先是一个帮助程序类,用于在编译器输出中打印模板参数值:
template<size_t A, size_t B> struct TAssertEquality {
static_assert(A==B, "Not equal");
static constexpr bool _cResult = (A==B);
};
然后你需要测试它的地方:
static constexpr bool _cIsEqual =
TAssertEquality<First::nbElementFirstEnum, Second::nbElementSecondEnum>::_cResult;
编译器错误消息如下所示:
注意:请参阅正在编译的类模板实例化"TAssertEquality<32,64>"的参考
这基本上有效,尽管可以通过一点努力来打破(通过将 V1 和 V2 的总和变成 256 的倍数)。所以,我认为你的解决方案更丑陋,但仍然更强大。
template <int V1, int V2> struct AssertEquality
{
static const char not_equal_warning = V1 + V2 + 256;
};
template <int V> struct AssertEquality<V, V>
{
static const bool not_equal_warning = 0;
};
#define ASSERT_EQUALITY(V1, V2) static_assert(
AssertEquality<static_cast<int>(V1),
static_cast<int>(V2)>::not_equal_warning == 0,
#V1 " != " #V2 );
// ...
ASSERT_EQUALITY(First::nbElementFirstEnum, Second::nbElementSecondEnum);
输出如下所示:
g++ -std=c++0x -c chksz.cpp
chksz.cpp: In instantiation of ‘const char AssertEquality<3, 2>::not_equal_warning’:
chksz.cpp:40:124: instantiated from here
chksz.cpp:5:53: warning: overflow in implicit constant conversion
chksz.cpp:40:1: error: static assertion failed: "First::nbElementFirstEnum != Second::nbElementSecondEnum"
作为参考,这个原始版本依赖于 gcc 打印static_assert
消息,即使布尔条件根本没有编译。
template <typename Enum1, int Max1, typename Enum2, int Max2>
struct AssertSameSizeEnums;
template <typename Enum1, int EnumMax, typename Enum2>
struct AssertSameSizeEnums<Enum1, EnumMax, Enum2, EnumMax> {};
// only define the special case where Max1 and Max2 have the same integer value
#define ASSERT_SAME_SIZE_ENUMS(E1, M1, E2, M2) static_assert(
sizeof(AssertSameSizeEnums<E1, E1::M1, E2, E2::M2>),
#E1 "::" #M1 " != " #E2 "::" #M2 );
enum class First {
a, b, c, nbElementFirstEnum,
};
enum class Second {
a, b, c, nbElementSecondEnum,
};
ASSERT_SAME_SIZE_ENUMS(First, nbElementFirstEnum, Second, nbElementSecondEnum);
请注意,我将枚举更改为强类型,因为否则枚举的常量名称会冲突。如果有弱类型枚举,则传递给宏的First
和Second
应命名封闭范围。
现在,如果我注释掉其中一个值(因此枚举的大小不同),我会得到:
g++ -std=c++0x -c chksz.cpp
chksz.cpp:25:113: error: invalid application of ‘sizeof’ to incomplete type ‘AssertSameSizeEnums<First, 3, Second, 2>’
chksz.cpp:25:1: error: static assertion failed: "First::nbElementFirstEnum != Second::nbElementSecondEnum"
看看整数值在不完整类型错误中是如何显示的,以及静态断言中的符号名称是如何显示的?
找到的解决方案,我们收到一条带有值和static_assert错误消息的警告消息。
template<int N>
struct TriggerOverflowWarning
{
static constexpr char value() { return N + 256; }
};
template <int N, int M, typename Enable = void>
struct CheckEqualityWithWarning
{
static constexpr bool value = true;
};
template <int N, int M>
struct CheckEqualityWithWarning<N, M, typename std::enable_if<N != M>::type>
{
static constexpr bool value = (TriggerOverflowWarning<N>::value() == TriggerOverflowWarning<M>::value());
};
static constexpr int a = 9;
static constexpr int b = 10;
static_assert(CheckEqualityWithWarning<a, b>::value, "Mismatch.");
这是 gcc 输出:
g++ -std=c++11 -c test.cpp
test.cpp: In instantiation of 'static constexpr char TriggerOverflowWarning<N>::value() [with int N = 10]':
test.cpp:18:112: required from 'constexpr const bool CheckEqualityWithWarning<9, 10>::value'
test.cpp:24:51: required from here
test.cpp:6:52: warning: overflow in implicit constant conversion [-Woverflow]
test.cpp: In instantiation of 'static constexpr char TriggerOverflowWarning<N>::value() [with int N = 9]':
test.cpp:18:112: required from 'constexpr const bool CheckEqualityWithWarning<9, 10>::value'
test.cpp:24:51: required from here
test.cpp:6:52: warning: overflow in implicit constant conversion [-Woverflow]
test.cpp:24:5: error: static assertion failed: Mismatch.
它基于这个解决方案: 编译时打印 sizeof(T)
带有 C++11
和 decltype
:
#define UTILITY_PP_STRINGIZE_(x) #x
#define UTILITY_PP_STRINGIZE(x) UTILITY_PP_STRINGIZE_(x)
#define STATIC_ASSERT_TRUE(exp, msg) static_assert(::utility::StaticAssertTrue<decltype(exp), (exp)>::value, "expression: "" UTILITY_PP_STRINGIZE(exp) "": " msg)
#define STATIC_ASSERT_TRUE1(exp, v1, msg)
static_assert(::utility::StaticAssertTrue<decltype(exp), (exp),
::utility::StaticAssertParam<decltype(v1), (v1)> >::value, "expression: "" UTILITY_PP_STRINGIZE(exp) "": " msg)
#define STATIC_ASSERT_TRUE2(exp, v1, v2, msg)
static_assert(::utility::StaticAssertTrue<decltype(exp), (exp),
::utility::StaticAssertParam<decltype(v1), (v1)>,
::utility::StaticAssertParam<decltype(v2), (v2)> >::value, "expression: "" UTILITY_PP_STRINGIZE(exp) "": " msg)
#define STATIC_ASSERT_TRUE3(exp, v1, v2, v3, msg)
static_assert(::utility::StaticAssertTrue<decltype(exp), (exp),
::utility::StaticAssertParam<decltype(v1), (v1)>,
::utility::StaticAssertParam<decltype(v2), (v2)>,
::utility::StaticAssertParam<decltype(v3), (v3)> >::value, "expression: "" UTILITY_PP_STRINGIZE(exp) "": " msg)
#define STATIC_ASSERT_TRUE4(exp, v1, v2, v3, v4, msg)
static_assert(::utility::StaticAssertTrue<decltype(exp), (exp),
::utility::StaticAssertParam<decltype(v1), (v1)>,
::utility::StaticAssertParam<decltype(v2), (v2)>,
::utility::StaticAssertParam<decltype(v3), (v3)>,
::utility::StaticAssertParam<decltype(v4), (v4)> >::value, "expression: "" UTILITY_PP_STRINGIZE(exp) "": " msg)
#define STATIC_ASSERT_FALSE(exp, msg) static_assert(::utility::StaticAssertFalse<decltype(exp), (exp)>::value, "expression: "" UTILITY_PP_STRINGIZE(exp) "": " msg)
#define STATIC_ASSERT_FALSE1(exp, v1, msg)
static_assert(::utility::StaticAssertFalse<decltype(exp), (exp),
::utility::StaticAssertParam<decltype(v1), (v1)> >::value, "expression: "" UTILITY_PP_STRINGIZE(exp) "": " msg)
#define STATIC_ASSERT_FALSE2(exp, v1, v2, msg)
static_assert(::utility::StaticAssertFalse<decltype(exp), (exp),
::utility::StaticAssertParam<decltype(v1), (v1)>,
::utility::StaticAssertParam<decltype(v2), (v2)> >::value, "expression: "" UTILITY_PP_STRINGIZE(exp) "": " msg)
#define STATIC_ASSERT_FALSE3(exp, v1, v2, v3, msg)
static_assert(::utility::StaticAssertFalse<decltype(exp), (exp),
::utility::StaticAssertParam<decltype(v1), (v1)>,
::utility::StaticAssertParam<decltype(v2), (v2)>,
::utility::StaticAssertParam<decltype(v3), (v3)> >::value, "expression: "" UTILITY_PP_STRINGIZE(exp) "": " msg)
#define STATIC_ASSERT_FALSE4(exp, v1, v2, v3, v4, msg)
static_assert(::utility::StaticAssertFalse<decltype(exp), (exp),
::utility::StaticAssertParam<decltype(v1), (v1)>,
::utility::StaticAssertParam<decltype(v2), (v2)>,
::utility::StaticAssertParam<decltype(v3), (v3)>,
::utility::StaticAssertParam<decltype(v4), (v4)> >::value, "expression: "" UTILITY_PP_STRINGIZE(exp) "": " msg)
#define STATIC_ASSERT_EQ(v1, v2, msg) static_assert(::utility::StaticAssertEQ<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: "" UTILITY_PP_STRINGIZE(v1) " == " UTILITY_PP_STRINGIZE(v2) "": " msg)
#define STATIC_ASSERT_NE(v1, v2, msg) static_assert(::utility::StaticAssertNE<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: "" UTILITY_PP_STRINGIZE(v1) " != " UTILITY_PP_STRINGIZE(v2) "": " msg)
#define STATIC_ASSERT_LE(v1, v2, msg) static_assert(::utility::StaticAssertLE<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: "" UTILITY_PP_STRINGIZE(v1) " <= " UTILITY_PP_STRINGIZE(v2) "": " msg)
#define STATIC_ASSERT_LT(v1, v2, msg) static_assert(::utility::StaticAssertLT<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: "" UTILITY_PP_STRINGIZE(v1) " < " UTILITY_PP_STRINGIZE(v2) "": " msg)
#define STATIC_ASSERT_GE(v1, v2, msg) static_assert(::utility::StaticAssertGE<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: "" UTILITY_PP_STRINGIZE(v1) " >= " UTILITY_PP_STRINGIZE(v2) "": " msg)
#define STATIC_ASSERT_GT(v1, v2, msg) static_assert(::utility::StaticAssertGT<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: "" UTILITY_PP_STRINGIZE(v1) " > " UTILITY_PP_STRINGIZE(v2) "": " msg)
namespace utility
{
template <typename T, T v>
struct StaticAssertParam
{
};
template <typename T, T v, typename ...Params>
struct StaticAssertTrue;
template <typename T, T v>
struct StaticAssertTrue<T, v>
{
static const bool value = (v ? true : false);
};
template <typename T, T v, typename ...Params>
struct StaticAssertTrue
{
static const bool value = (v ? true : false);
static_assert(v ? true : false, "StaticAssertTrue with parameters failed.");
};
template <typename T, T v, typename ...Params>
struct StaticAssertFalse;
template <typename T, T v>
struct StaticAssertFalse<T, v>
{
static const bool value = (v ? false : true);
};
template <typename T, T v, typename ...Params>
struct StaticAssertFalse
{
static const bool value = (v ? false : true);
static_assert(v ? false : true, "StaticAssertFalse with parameters failed.");
};
template <typename U, typename V, U u, V v>
struct StaticAssertEQ
{
static const bool value = (u == v);
static_assert(u == v, "StaticAssertEQ failed.");
};
template <typename U, typename V, U u, V v>
struct StaticAssertNE
{
static const bool value = (u != v);
static_assert(u != v, "StaticAssertNE failed.");
};
template <typename U, typename V, U u, V v>
struct StaticAssertLE
{
static const bool value = (u <= v);
static_assert(u <= v, "StaticAssertLE failed.");
};
template <typename U, typename V, U u, V v>
struct StaticAssertLT
{
static const bool value = (u < v);
static_assert(u < v, "StaticAssertLT failed.");
};
template <typename U, typename V, U u, V v>
struct StaticAssertGE
{
static const bool value = (u >= v);
static_assert(u >= v, "StaticAssertGE failed.");
};
template <typename U, typename V, U u, V v>
struct StaticAssertGT
{
static const bool value = (u > v);
static_assert(u > v, "StaticAssertGT failed.");
};
}
用法:
struct A
{
int a[4];
};
#define Float1 1.1f
#define Float2 1.2f
int main()
{
static const int a = 3;
static const long b = 5;
static const long c = 7;
static const long d = 9;
STATIC_ASSERT_TRUE4(a == b && c == d, a, b, c, d, "long_expression_with_multiple_integral_variables");
#pragma message("----------------------------------------")
STATIC_ASSERT_TRUE(Float1 == Float2, "expression_with_floats");
#pragma message("----------------------------------------")
STATIC_ASSERT_EQ(10, sizeof(A), "simple_integral_expression_1");
#pragma message("----------------------------------------")
STATIC_ASSERT_EQ(11, sizeof(A), "simple_integral_expression_2");
return 0;
}
MSVC2017:
source_file.cpp(72): error C2338: StaticAssertTrue with parameters failed.
source_file.cpp(148): note: see reference to class template instantiation 'utility::StaticAssertTrue<bool,false,utility::StaticAssertParam<const int,3>,utility::StaticAssertParam<const long,5>,utility::StaticAssertParam<const long,7>,utility::StaticAssertParam<const long,9>>' being compiled
source_file.cpp(148): error C2338: expression: "a == b && c == d": long_expression_with_multiple_integral_variables
----------------------------------------
source_file.cpp(152): error C2338: expression: "1.1f == 1.2f": expression_with_floats
----------------------------------------
source_file.cpp(95): error C2338: StaticAssertEQ failed.
source_file.cpp(156): note: see reference to class template instantiation 'utility::StaticAssertEQ<int,size_t,10,16>' being compiled
source_file.cpp(156): error C2338: expression: "10 == sizeof(A)": simple_integral_expression_1
----------------------------------------
source_file.cpp(160): error C2338: expression: "11 == sizeof(A)": simple_integral_expression_2
GCC 4.8.x:
<source>: In instantiation of 'struct utility::StaticAssertTrue<bool, false, utility::StaticAssertParam<const int, 3>, utility::StaticAssertParam<const long int, 5l>, utility::StaticAssertParam<const long int, 7l>, utility::StaticAssertParam<const long int, 9l> >':
<source>:148:5: required from here
<source>:72:9: error: static assertion failed: StaticAssertTrue with parameters failed.
static_assert(v ? true : false, "StaticAssertTrue with parameters failed.");
^
<source>: In function 'int main()':
<source>:18:5: error: static assertion failed: expression: "a == b && c == d": long_expression_with_multiple_integral_variables
static_assert(::utility::StaticAssertTrue<decltype(exp), (exp),
^
<source>:148:5: note: in expansion of macro 'STATIC_ASSERT_TRUE4'
STATIC_ASSERT_TRUE4(a == b && c == d, a, b, c, d, "long_expression_with_multiple_integral_variables");
^
<source>:150:63: note: #pragma message: ----------------------------------------
#pragma message("----------------------------------------")
^
<source>:4:41: error: static assertion failed: expression: "1.1f == 1.2f": expression_with_floats
#define STATIC_ASSERT_TRUE(exp, msg) static_assert(::utility::StaticAssertTrue<decltype(exp), (exp)>::value, "expression: "" UTILITY_PP_STRINGIZE(exp) "": " msg)
^
<source>:152:5: note: in expansion of macro 'STATIC_ASSERT_TRUE'
STATIC_ASSERT_TRUE(Float1 == Float2, "expression_with_floats");
^
<source>:154:63: note: #pragma message: ----------------------------------------
#pragma message("----------------------------------------")
^
<source>: In instantiation of 'struct utility::StaticAssertEQ<int, long unsigned int, 10, 16ul>':
<source>:156:5: required from here
<source>:95:9: error: static assertion failed: StaticAssertEQ failed.
static_assert(u == v, "StaticAssertEQ failed.");
^
<source>:44:41: error: static assertion failed: expression: "10 == sizeof(A)": simple_integral_expression_1
#define STATIC_ASSERT_EQ(v1, v2, msg) static_assert(::utility::StaticAssertEQ<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: "" UTILITY_PP_STRINGIZE(v1) " == " UTILITY_PP_STRINGIZE(v2) "": " msg)
^
<source>:156:5: note: in expansion of macro 'STATIC_ASSERT_EQ'
STATIC_ASSERT_EQ(10, sizeof(A), "simple_integral_expression_1");
^
<source>:158:63: note: #pragma message: ----------------------------------------
#pragma message("----------------------------------------")
^
<source>: In instantiation of 'struct utility::StaticAssertEQ<int, long unsigned int, 11, 16ul>':
<source>:160:5: required from here
<source>:95:9: error: static assertion failed: StaticAssertEQ failed.
static_assert(u == v, "StaticAssertEQ failed.");
^
<source>:44:41: error: static assertion failed: expression: "11 == sizeof(A)": simple_integral_expression_2
#define STATIC_ASSERT_EQ(v1, v2, msg) static_assert(::utility::StaticAssertEQ<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: "" UTILITY_PP_STRINGIZE(v1) " == " UTILITY_PP_STRINGIZE(v2) "": " msg)
^
<source>:160:5: note: in expansion of macro 'STATIC_ASSERT_EQ'
STATIC_ASSERT_EQ(11, sizeof(A), "simple_integral_expression_2");
^
上述问题在于它们依赖于警告,这些警告可能存在于不同的编译器上,也可能不存在,并且可能不是每个人都一直打开。(事实上,其中一个在打开所有警告的情况下不会显示 Clang 的值。
此解决方案借鉴了此处的其他解决方案,但利用了类型系统,因此根据C++标准,始终是一个实际错误。不幸的是,这确实会提前停止,并且不会触发static_assert错误本身,这是一个缺点。这已在 GCC 5.3 和 Clang 3.7 上进行了测试,没有打开任何警告。
template <long V1, long V2>
struct StaticAssertEquality
{
static constexpr void* NotEqualError() { return V1 + V2; }
};
template <long V>
struct StaticAssertEquality<V, V>
{
static constexpr bool NotEqualError = true;
};
#define STATIC_ASSERT_LONG_EQUALITY(V1, V2)
static_assert(
StaticAssertEquality<static_cast<long>(V1),
static_cast<long>(V2)>::NotEqualError,
#V1 " != " #V2)
// ...
STATIC_ASSERT_LONG_EQUALITY(1, 2);
显然,它不适用于所有未签名的长。作为额外的安全捕获,宏可以包括第二个简单的static_assert(V1 == V2, #V1 " != " #V2);
,以捕获类型转换中的任何杂散意外等式。
Clang 的输出如下所示:
file.cpp: error: cannot initialize return object of type 'void *' with an rvalue of type 'long'
static constexpr void* NotEqualError() { return V1 + V2; }
^~~~~~~
file.cpp: note: in instantiation of member function 'StaticAssertEquality<1, 2>::NotEqualError' requested here
STATIC_ASSERT_LONG_EQUALITY(1, 2);
^
file.cpp: note: expanded from macro 'STATIC_ASSERT_LONG_EQUALITY'
static_cast<long>(V2)>::NotEqualError,
^
1 error generated.
并使用 GCC 输出:
file.cpp: In instantiation of 'static constexpr void* StaticAssertEquality<V1, V2>::NotEqualError() [with long V1 = 1; long V2 = 2]':
file.cpp: required from here
file.cpp: error: invalid conversion from 'long' to 'void*' [-fpermissive]
static constexpr void* NotEqualError() { return V1 + V2; }
^
g++.exe: failed with exit code 1 (00000001)
另一种C++11
方法,只是查找深度嵌套类型或编译时值。
#include <vector>
// generates compilation error and shows real type name (and place of declaration in some cases) in an error message, useful for debugging boost::mpl like recurrent types
#define UTILITY_TYPE_LOOKUP_BY_ERROR(type_name)
using _type_lookup_t = decltype((*(typename ::utility::type_lookup<type_name >::type*)0).operator ,(*(::utility::dummy*)0))
// lookup compile time template typename value
#define UTILITY_PARAM_LOOKUP_BY_ERROR(static_param)
UTILITY_TYPE_LOOKUP_BY_ERROR(STATIC_ASSERT_PARAM(static_param))
#define STATIC_ASSERT_PARAM(v1) ::utility::StaticAssertParam<decltype(v1), (v1)>
namespace utility
{
template <typename T>
struct type_lookup
{
using type = T;
};
struct dummy {};
template <typename T, T v>
struct StaticAssertParam
{
};
}
struct test
{
char a[123];
double b[15];
std::vector<int> c;
};
UTILITY_PARAM_LOOKUP_BY_ERROR(sizeof(test));
MSVC2017
error C2039: ',': is not a member of 'utility::StaticAssertParam<size_t,272>'
GCC 4.8.x:
<source>:5 : 103 : error : 'using type = struct utility::StaticAssertParam<long unsigned int, 272ul>' has no member named 'operator,'
using _type_lookup_t = decltype((*(typename ::utility::type_lookup<type_name >::type*)0).operator ,(*(::utility::dummy*)0))
^
<source> : 9 : 5 : note : in expansion of macro 'UTILITY_TYPE_LOOKUP_BY_ERROR'
UTILITY_TYPE_LOOKUP_BY_ERROR(STATIC_ASSERT_PARAM(static_param))
^
<source> : 36 : 1 : note : in expansion of macro 'UTILITY_PARAM_LOOKUP_BY_ERROR'
UTILITY_PARAM_LOOKUP_BY_ERROR(sizeof(test));
^
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 如何在openssl-ecc中获取十六进制格式的私钥
- 当使用比格式支持的精度更高的精度来显示数字时,会写出什么数据
- 将信息输入到下面显示的结构向量中的正确语法/格式是什么
- C++ 我的开关格式中的循环不允许我显示菜单选项或接受输入?
- 如何从文件中读取并将内容存储在动态 2D 数组中并以网格格式显示
- 如何设置数字格式以显示C 中的所有小数位数
- 如何以某种格式为用户显示对象向量
- C++显示具有与.bmp格式不同的 SDL2 的图像
- 在编译时以 static_assert() 格式显示整数
- QT显示双重号码,没有指数格式
- 在图片框中显示cv::Mat格式的网络摄像头提要
- 以C++格式全精度显示浮点数
- 如何不仅要求动态2D阵列的行数和列数,还要求以表格格式显示
- fstream以txt格式显示所有文本
- QTextEdit显示的块中图像后的文本格式
- 使用'uxxxx'格式定义的字符显示错误的字符
- 在屏幕上以良好的格式显示时间
- 在 cout 中将数字十进制格式显示为指数