ホームページ >バックエンド開発 >C++ >グローバル変数や変更可能な状態を使用せずに、コンパイル時カウンターを C で実装するにはどうすればよいですか?

グローバル変数や変更可能な状態を使用せずに、コンパイル時カウンターを C で実装するにはどうすればよいですか?

Susan Sarandon
Susan Sarandonオリジナル
2024-12-25 16:52:10846ブラウズ

How Can Compile-Time Counters Be Implemented in C   Without Using Global Variables or Modifiable State?

C のコンパイル時カウンター

テンプレート メタプログラミングの機能的性質にもかかわらず、グローバル変数や変更可能な状態は、コンパイル時カウンターの実装にすぐには利用できません。ただし、以下に示すように、名前空間スコープの機能は、テンプレートの使用を最小限に抑えて実現できます。

関数ルックアップを使用して、宣言された関数のセットを通じて数値状態を追跡できます。次のコードに示すように、

>
template< size_t n > // Return a number through function lookup.
struct cn // The function returns cn<n>.
{ char data[ n + 1 ]; }; // The caller uses (sizeof fn() - 1).

template< typename id, size_t n, size_t acc >
cn< acc > seen( id, cn< n >, cn< acc > ); // Default fallback case.

#define counter_read( id ) \
( sizeof seen( id(), cn< 1 >, cn< \
( sizeof seen( id(), cn< 2 >, cn< \
( sizeof seen( id(), cn< 4 >, cn< \
( sizeof seen( id(), cn< 8 >, cn< \
( sizeof seen( id(), cn< 16 >, cn< \
( sizeof seen( id(), cn< 32 >, cn< 0 \
/* Add more as desired; trimmed for Stack Overflow code block. */ \
                      >() ).data - 1 ) \
                      >() ).data - 1 ) \
                      >() ).data - 1 ) \
                      >() ).data - 1 ) \
                      >() ).data - 1 ) \
                      >() ).data - 1 )

#define counter_inc( id ) \
cn< counter_read( id ) + 1 > \
seen( id, cn< ( counter_read( id ) + 1 ) &amp; ~ counter_read( id ) >, \
          cn< ( counter_read( id ) + 1 ) &amp; counter_read( id ) > )

クイックデモ:

struct my_cnt {};

int const a = counter_read( my_cnt );
counter_inc( my_cnt );
counter_inc( my_cnt );
counter_inc( my_cnt );
counter_inc( my_cnt );
counter_inc( my_cnt );

int const b = counter_read( my_cnt );

counter_inc( my_cnt );

#include <iostream>

int main() {
    std::cout << a << ' ' << b << '\n';

    std::cout << counter_read( my_cnt ) << '\n';
}

C 11 アップデート:

C 11 の constexpr を使用する更新バージョンでは、sizeof:

#define COUNTER_READ_CRUMB( TAG, RANK, ACC ) counter_crumb( TAG(), constant_index< RANK >(), constant_index< ACC >() )
#define COUNTER_READ( TAG ) COUNTER_READ_CRUMB( TAG, 1, COUNTER_READ_CRUMB( TAG, 2, COUNTER_READ_CRUMB( TAG, 4, COUNTER_READ_CRUMB( TAG, 8, \
    COUNTER_READ_CRUMB( TAG, 16, COUNTER_READ_CRUMB( TAG, 32, COUNTER_READ_CRUMB( TAG, 64, COUNTER_READ_CRUMB( TAG, 128, 0 ) ) ) ) ) ) )

#define COUNTER_INC( TAG ) \
constexpr \
constant_index< COUNTER_READ( TAG ) + 1 > \
counter_crumb( TAG, constant_index< ( COUNTER_READ( TAG ) + 1 ) &amp; ~ COUNTER_READ( TAG ) >, \
                                                constant_index< ( COUNTER_READ( TAG ) + 1 ) &amp; COUNTER_READ( TAG ) > ) { return {}; }

#define COUNTER_LINK_NAMESPACE( NS ) using NS::counter_crumb;

template< std::size_t n >
struct constant_index : std::integral_constant< std::size_t, n > {};

template< typename id, std::size_t rank, std::size_t acc >
constexpr constant_index< acc > counter_crumb( id, constant_index< rank >, constant_index< acc > ) { return {}; } // found by ADL via constant_index
の使用が排除されます。

これにより、カウンターごとに個別の名前空間が必要なくなり、より便利になります。複数の名前空間で使用します。

以上がグローバル変数や変更可能な状態を使用せずに、コンパイル時カウンターを C で実装するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。