「C++のconstexprの値がおかしいんだけど、static_assertで間違った値表示できないの?」と聞かれました。
できねぇんだな、これが
C++11からstatic_assertはあるというのに、何故static_assert_eqやstatic_assert_ltとかがないのだろう。謎で仕方がないです。
#include <cassert> constexpr int x = 10; static_assert(x == 1, "x?");
これをg++でコンパイルすると、以下の様なエラーになります。
xが何だかは全然分からないですね。
static assertion failed: x? 4 | static_assert(x == 1, "x?"); | ~~^~~~~
static_assertのメッセージには、ストリングリテラルしか入れられないので、動的に生成することもできないです。 C++20でconstexprにおけるメモリ確保までできる様になるんだから、そこら辺も緩和して欲しいところです。
組み込みの定数計算ぐらいならなんとかなるかも
表示できないと言いましたが、整数値なら、裏技的に値を表示する方法があります。
constexpr int x = 10; template<int NUMBER> struct test { static constexpr bool value=true; static_assert(NUMBER == 1,"test<NUMBER>"); }; static_assert(test<x>::value,"");
これのg++のエラーは以下の様になります。
foo.cpp: In instantiation of 'struct test<10>': foo.cpp:15:22: required from here foo.cpp:12:24: error: static assertion failed: test<NUMBER> 12 | static_assert(NUMBER == 1,"test<NUMBER>"); | ~~~~~~~^~~~~
そう、一度テンプレートパラメータに入れてしまうと、「foo.cpp: In instantiation of 'struct test<10>':」ここ(赤字)に値が出るんです。
ちなみに、clang++だと、NUMBER==1じゃなくて、10==1と表示してくれます。凄いね。
複雑なクラスなど使わない組み込みで、整数を計算するだけのconstexprなら、これで十分な場合も多々あると思います。
というわけで、まとめておいた
一々書くのも面倒くさいと言うことで、まとめておきました。
こんな感じで使えます。
#include "sassert.h" // @return x * x constexpr int pow(int x){return x + x;} SASSERT_EQ(pow(10),100); // 10*10 == 100 SASSERT_NE(pow(10),20); // 10*10 != 20 SASSERT_LT(pow(1),2); // 1*1 < 2 SASSERT_GT(pow(10),50); // 10*10 > 50 SASSERT_LTE(pow(10),100);// 10*10 <= 100 SASSERT_GTE(pow(10),100);// 10*10 >= 100
エラー時の値は「nds::assert_○<型, 値, 期待値, ファイル行 >」という形で表示されるので、その言葉を探してください。IAR Embedded Workbench等で使う場合は、エラーログを右クリックし、ログのフィルタリングを無し(全て)にして表示してください。
g++だとこんな感じ。
include/sassert.h: In instantiation of 'struct nds::assert_eq<int, 20, 100, nds::line<6> >': foo.cpp:6:1: required from here include/sassert.h:54:17: error: static assertion failed: Value == Expected 54 | static_assert(value,"Value == Expected"); | ^~~~~ include/sassert.h:31:45: error: static assertion failed: pow(10) == 100 30 | static_assert(::nds::assert_##op <::nds::assert_type_t<decltype(x)>,\ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 31 | x,y,::nds::line<__LINE__>>::value,#x message #y) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~ include/sassert.h:22:27: note: in expansion of macro '__NDS__ASSERT_BASE' 22 | # define SASSERT_EQ(x,y) __NDS__ASSERT_BASE(eq," == ",x,y) | ^~~~~~~~~~~~~~~~~~ foo.cpp:6:1: note: in expansion of macro 'SASSERT_EQ' 6 | SASSERT_EQ(pow(10),100); // 10*10 == 100 | ^~~~~~~~~~
「include/sassert.h: In instantiation of 'struct nds::assert_eq<int, 20, 100, nds::line<6> >':」の所に、pow(10)の間違った結果が出ています。
ライセンスはCC0なので(Unlicenseとどっちがいいの?)、適当に改変して結構です。
………static_assert_eqとかC++で対応してくれないかなぁ。