プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

static_assertで比較した値を表示したい

「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なら、これで十分な場合も多々あると思います。

 

というわけで、まとめておいた

 一々書くのも面倒くさいと言うことで、まとめておきました。

github.com

 こんな感じで使えます。

#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++で対応してくれないかなぁ。