C ++构造,其行为类似于__COUNTER__宏

时间:2014-04-21 21:46:10

标签: c++ templates macros template-meta-programming

我有一组C ++类,每个类必须声明一个唯一的顺序id作为编译时常量。 为此,我使用__COUNTER__内置宏转换为一个整数,该整数在每次出现时都会递增。 ids不需要遵循严格的命令。唯一的要求是它们是顺序的并从0开始:

class A {
public:
    enum { id = __COUNTER__ };
};

class B {
public:
    enum { id = __COUNTER__ };
};

// etcetera ...

我的问题是:有没有办法使用C ++构造实现相同的结果,例如模板?

4 个答案:

答案 0 :(得分:4)

以下是使用__LINE__宏和模板执行此操作的可能方法:

template <int>
struct Inc
{
    enum { value = 0 };
};

template <int index>
struct Id
{
    enum { value = Id<index - 1>::value + Inc<index - 1>::value };
};

template <>
struct Id<0>
{
    enum { value = 0 };
};

#define CLASS_DECLARATION(Class) \
template <> \
struct Inc<__LINE__> \
{ \
    enum { value = 1 }; \
}; \
 \
struct Class \
{ \
    enum { id = Id<__LINE__>::value }; \
private:

使用示例:

CLASS_DECLARATION(A)
    // ...
};

CLASS_DECLARATION(B)
    // ...
};

CLASS_DECLARATION(C)
    // ...
};

请参阅live example

答案 1 :(得分:3)

明确的链接是否可以接受?

class A {
public:
    static const unsigned int id = 1;
};

class B {
public:
    static const unsigned int id = A::id+1;
};

这种方法的优点是你总能获得相同的Id,无论你的编译器是什么,你都知道它是什么。虽然采用__LINE____COUNTER__方法可能无法预测。缺点是,通过链接你的班级必须始终知道链上的前一个。

使用模板(和C ++ 11):

template <typename... T>
class Identificable;

template <>
class Identificable<> {
public:
    static const unsigned int id = 1;   
};

template <typename Prev>
class Identificable<Prev> {
public:
    static const unsigned int id = Prev::id+1;
};

class A : public Identificable<> {
public:
};

class B : public Identificable<A> {
public:
};

答案 2 :(得分:2)

标准C ++具有 __LINE__ 宏。

也就是说,__LINE__是一个“C ++构造”,根据要求,与__COUNTER__形成鲜明对比,而不是。{/ p>

__LINE__与Visual C ++的__COUNTER__的不同之处在于,当使用某个编译选项时,至少早期版本的Visual C ++会产生__LINE__的乱码扩展。


根据您的需求,您可以简单地使用type_info个实例进行身份识别。 C ++ 11增加了对比较type_info的一般支持,称为 std::typeindex 。这意味着您可以使用标准集合。

答案 3 :(得分:1)

  

有没有办法使用C ++构造实现相同的结果,例如   作为模板?

是的,有:-)基本思想是使用链接分配的ID,这避免了使用__COUNTER____LINE__或之前提出的其他方法,并且不需要注入&#34;额外&#34;信息到类型定义。

以下是使用模板元编程在v1中为在C ++ 03上实现的计数器提出的解决方案的简要说明。两个模板特化ID_by_TT_by_ID用于在编译时定义链接type <=> ID。类型的ID是枚举常量。如果未定义链接,ID_by_T<type>::ID将返回-1T_by_ID<undefinedID>::type将返回null_t预定义类型。宏DEF_TYPE_ID(type_name)会在定义ID链接时生成新的type <=> ID

此方法基于宏重定义:当使用#undef未定义宏时,其值将扩展为C ++代码。例如:

DEF_TYPE_ID(int)
#undef  PREV_TYPE
#define PREV_TYPE int

DEF_TYPE_ID使用以下调用宏PREV_TYPE的先前定义:ID_T_pair<type_name, ID_by_T<PREV_TYPE>::ID+1>。这就是为什么我说关于链接分配的ID。