模板与非模板类,编译器之间的不同行为

时间:2014-05-07 18:37:39

标签: c++ templates

我在某些应用程序中使用编译时计数器,它非常有用。昨天我想用gcc编译一个程序(之前我使用的是msvc),并且计算器的行为在模板化的类中发生了变化(它在模板类中不再起作用)。

过于简化的代码:

// Maximum value the counter can hold
#define MAX_COUNT 64

// Used to store a number as the size of the structure
template<unsigned int n> struct Count { bool data[n]; };

// Used to overload functions while automatically selecting the
// right one based on the counter value (see following code)
template<int n> struct cn : public cn<n-1> {};
template<> struct cn<0> {};

struct Test
{
    #define COUNT \
        ((sizeof(f(cn<MAX_COUNT + 1>())) / sizeof(bool)) - 1)

    static Count<1> f(cn<1>);

    /*
        f(cn<65>()) will 'call' f(cn<1>) and return a Count<1> with size 1
        -> count = 0;
    */
    static const int a = COUNT;
    static Count<COUNT + 2> f(cn<COUNT + 2>); // increase counter

    /*
        now Count<2> f(cn<2>) is defined, so:
        f(cn<65>()) will 'call' f(cn<2>) and return a Count<2> with size 2
        -> count = 1;
    */
    static const int b = COUNT;
};

这个想法是使用函数重载,如果你测试上面的代码will work perfectlya == 0b == 1)。

但是,如果结构Test是模板(例如,只需在声明之前添加template<something>,不需要使用模板参数),the counter breaks我最终会a == b == 1。它还暗示在这些条件下不可能增加计数器。

所以这是我的问题:

  • 这里有哪些模板规则?
  • 为什么会有这种特殊行为?
  • 您是否知道计数器的实际工作方式?

注意:我想要一个与旧编译器兼容的C ++ 03答案(即使我很想知道C ++ 11的特定情况的规则是否有所改变)

编辑:有些输出:

  • VC2010:

    Templated
    a = 0
    b = 1
    
  • GCC 4.8.1

    Templated
    a = 1
    b = 1
    
  • Clang 3.4(感谢dyp):

    Templated
    a = 0
    b = 1
    

编辑2

GCC似乎将Count作为依赖名称,observable here(感谢dyp)。我在gcc bugzilla here发布了一个错误报告。

1 个答案:

答案 0 :(得分:0)

这可能是C ++中两阶段名称查找的属性。这是C ++ 03的一个特性,也存在于C ++ 11中。 LLVM项目对此功能进行了article,并将其Clang编译器与GCC和Visual C ++进行了比较。 GCC和Visual C ++不支持此功能,但Visual C ++确实有一种处理名称查找的方法,它允许依赖于两阶段查找的代码比GCC更频繁地工作。根据文章,它还允许非有效C ++代码的代码也能正常工作。

编辑:我误读了这篇文章,GCC确实实现了两阶段查找,但它可以选择延迟查找直到模板实例化。这似乎是GCC中的一个错误。