尽管模板元编程具有函数性质,但全局变量或可修改状态并不容易用于实现编译时计数器。但是,如下所示,可以通过最少使用模板来实现命名空间范围功能。
可以使用函数查找来通过声明的函数集来跟踪数字状态,如以下代码所示:
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 ) & ~ counter_read( id ) >, \ cn< ( counter_read( id ) + 1 ) & 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 ) & ~ COUNTER_READ( TAG ) >, \ constant_index< ( COUNTER_READ( TAG ) + 1 ) & 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中文网其他相关文章!