【问题标题】:Increase compile-time variable with every instantiation of a generic class每次实例化泛型类时增加编译时变量
【发布时间】:2013-01-28 10:34:01
【问题描述】:

我有这门课:

template <typename T, uint64_t N>
struct Probe {
  static const uint64_t Counter = N;
  typedef T Type;
};

我用作:

typedef Probe <int, 0> FirstIntProbe;
typedef Probe <int, 1> SecondIntProbe;
typedef Probe <float, 2> FloatProbe;

是否可以创建一个编译时\宏方法,它允许我在不指定第二个参数的情况下实例化此类,例如:

typedef Probe <int, Something?> FirstIntProbe;
typedef Probe <int, Something?> SecondIntProbe;
typedef Probe <float, Something?> FloatProbe;

我认为这是不可能的,但我又看到人们用 C++ 做我以前认为不可能的事情。


更新:

  • 不需要加一,重要的是 每个探头都有自己的编号。
  • 不需要唯一 跨不同 .cpp 文件\翻译单元的编号。

【问题讨论】:

  • N 的值从 0 开始并且始终是连续的是否重要?那么跨翻译单元的行为呢?一些编译器有__COUNTER__,这对于您的目的可能已经足够了。

标签: c++ c++11 generic-programming


【解决方案1】:

您可以考虑使用__COUNTER__ 宏,它是一个编译器扩展(但在GCCMSVC 等上受支持)。请注意,__COUNTER__ 仅在每个翻译单元中是唯一的,即每个 .cpp 文件。

编辑:在多个翻译单元中包含标题是可以的。此示例链接并运行良好(基于 GCC 4.5):

probe.h

template <typename T, int N>
struct Probe {
    typedef T Type;
};

#define DECLARE_PROBE(type) typedef struct Probe<type, __COUNTER__>

main.cpp

#include "test.h"

DECLARE_PROBE(int) intprobe;
DECLARE_PROBE(float) floatprobe;

int main(int argc, char** argv) {
    intprobe ip;
    floatprobe fp;
    return 0;
}

test.cpp

#include "test.h"

DECLARE_PROBE(int) intprobe;
DECLARE_PROBE(float) floatprobe;

static intprobe ip;
static floatprobe fp;

【讨论】:

  • 这如何工作? __COUNTER__ 针对每个翻译单元中的每次使用进行扩展。因此,如果Probe 在标题中,并且包含在多个翻译单元中,由于违反了一个定义规则,您将有未定义的行为,即使Probe 仅存在于单个翻译单元中,如果__COUNTER__ 是宏的一部分,它只会被扩展一次。
  • 正如我所提到的,__COUNTER__ 只是每个翻译单元唯一的。 __COUNTER__ 在宏使用中扩展得很好;试试#define DECLARE_PROBE(type) typedef struct Probe&lt;type, __COUNTER__&gt; 的大小。
  • 我已经用示例用法编辑了答案。将模板类和宏定义包含在一个公共头文件中是非常好的。
  • 如果我在两个不同的翻译单元中调用 DECLARE_PROBE?
  • @JamesKanze:我刚刚做了,在那个例子中。只要定义相同,ODR 就可以使用多个定义(如果您真的想查找它,请参见第 3.2.5 节)。想想看——如果不是这样,每次你在不同的翻译单元中实例化 std::vector&lt;int&gt; 时,你的编译器都会出错......
【解决方案2】:

其实很简单如果你不需要积分 常量表达式(即您没有使用 Counter 作为 数组等的维度):只需使用全局静态 计数器(或将其放在非模板基类中),以及 每次在初始化中使用它时都会增加它。 比如:

int currentProbeCounter;

template <typename T>
struct Probe
{
    static int const counter;
    //  ...
};

template <typename T>
const int Probe<T>::counter = ++ currentProbeCounter;

请注意,这只会分配Probe&lt;T&gt;::counter 当(或如果)你使用它时给定的类型;你可能想用它 在Probe 的构造函数中(即使你不需要) 确保它的创建。 (另一方面,如果你从不使用它, 谁在乎它是否从未被创建。)

【讨论】:

  • 为计数器使用一个实际的静态变量需要编译器为其实例化存储(和初始化);这可能比为计数器使用常量模板参数更可取,后者不需要存储并允许编译器对其进行优化并将其折叠成表达式。
  • @sheu 但是没有其他解决方案(据我所知)有效。一旦您使用多个翻译单元,任何使用宏的操作都会失败。
  • 除了上面的宏吗?
  • @sheu 如果您将所有声明限制在同一个文件中,上面的宏 有效。在这种情况下,您不妨像其他人一样只使用__LINE__,而不必为非便携式解决方案而烦恼。
  • 好吧,不幸的是我确实需要一个编译时积分常数
【解决方案3】:

您可以使用Boost.Preprocessor 为您完成这项工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-03
    • 2011-04-02
    相关资源
    最近更新 更多