C ++是否支持编译时计数器? [英] Does C++ support compile-time counters?

查看:152
本文介绍了C ++是否支持编译时计数器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



不幸的是,模板元编程本质上是一种功能语言



或者是?






请求的示例代码:

  #include< iostream> 

int const a = counter_read;
counter_inc;
counter_inc;
counter_inc;
counter_inc;
counter_inc;

int const b = counter_read;

int main(){
std :: cout< a<< ''<< b<< '\\\
'; // print0 5

counter_inc_t();
counter_inc_t();
counter_inc_t();

std :: cout<< counter_read<< '\\\
'; // print8

struct {
counter_inc_t d1;
char x [counter_read];
counter_inc_t d2;
char y [counter_read];
} ls;

std :: cout<< size of ls.x < ''<< sizeof ls.y< '\\\
'; // print9 10
}


解决方案

嗯...是的,模板元编程缺乏预期的副作用。我被错误的老版本的GCC和标准中的一些不清楚的措辞误导相信所有这些功能是可能的。



但是,至少命名空间 - 根本无需使用模板就可以实现范围功能。函数查找可以从一组声明的函数中提取数字状态,如下所示。



库代码:

  template< size_t n> //此类型通过函数查找返回一个数字。 
struct cn //函数返回cn< n> ;.
{char data [n + 1]; }; //调用者使用(sizeof fn() - 1)。

template< typename id,size_t n,size_t acc>
cn < acc> see(id,cn n,cn acc); //默认回退大小写。

/ *通过查找最后定义的重载来计算计数器。
每个函数在定义时会更改低阶
函数的查找顺序。 * /
#define counter_read(id)\
(size of seen(id(),cn 1(),cn <\
cn 2(),cn <\
(size of seen(id(),cn 4(),cn <\
8,(cn,cn,cn,cn,cn,cn,cn,cn,cn,cn, ;(),cn <0 \
/ *根据需要添加更多;为Stack Overflow代码块修剪* / \
>()).data - 1)\
>()).data - 1)\
>()).data - 1)\
>()).data - 1)\
> ;()).data - 1)\
>()).data - 1)

/ *定义一个新的函数,其中place-value等于被翻转为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<< '\\\
';

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



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 {}; } //由ADL通过constant_index找到

http://ideone.com/KMMBAR



声明应放在命名空间中,除 counter_crumb 之外的宏应该是完全限定的。通过与 constant_index 类型的ADL关联可找到 counter_crumb 模板。


$ b b

COUNTER_LINK_NAMESPACE 巨集可用于增加多个命名空间范围内的一个计数器。


For the purpose of introspection, sometimes I've wanted to automatically assign serial numbers to types, or something similar.

Unfortunately, template metaprogramming is essentially a functional language, and as such lacks global variables or modifiable state which would implement such a counter.

Or is it?


Example code by request:

#include <iostream>

int const a = counter_read;
counter_inc;
counter_inc;
counter_inc;
counter_inc;
counter_inc;

int const b = counter_read;

int main() {
    std::cout << a << ' ' << b << '\n'; // print "0 5"

    counter_inc_t();
    counter_inc_t();
    counter_inc_t();

    std::cout << counter_read << '\n'; // print "8"

    struct {
        counter_inc_t d1;
        char x[ counter_read ];
        counter_inc_t d2;
        char y[ counter_read ];
    } ls;

    std::cout << sizeof ls.x << ' ' << sizeof ls.y << '\n'; // print "9 10"
}

解决方案

Well… yes, template metaprogramming lacks side effects as it is intended. I was misled by a bug in older versions of GCC and a little unclear wording in the Standard to believe that all those features were possible.

However, at least the namespace-scope functionality can be achieved with little use of templates at all. Function lookup can extract numeric state from the set of declared functions, as demonstrated below.

Library code:

template< size_t n > // This type returns 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.

/* Evaluate the counter by finding the last defined overload.
   Each function, when defined, alters the lookup sequence for lower-order
   functions. */
#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 a single new function with place-value equal to the bit flipped to 1
   by the increment operation.
   This is the lowest-magnitude function yet undefined in the current context
   of defined higher-magnitude functions. */
#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 ) > )

Quick demo (see it run):

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 Update

Here is an updated version using C++11 constexpr in place of 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

http://ideone.com/KMMBAR

The declarations should be put inside a namespace, and all names used in the macros except counter_crumb should be fully qualified. The counter_crumb template is found via ADL association with the constant_index type.

The COUNTER_LINK_NAMESPACE macro can be used to increment one counter in the scope of multiple namespaces.

这篇关于C ++是否支持编译时计数器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆