【问题标题】:Template vs non-template class, different behavior across compilers模板与非模板类,编译器之间的不同行为
【发布时间】:2014-05-07 18:37:38
【问题描述】:

我在一些应用程序中使用了编译时计数器,它真的很有用。昨天我想用 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&lt;something&gt;,则无需使用模板参数),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 中发布了一个错误报告。

【问题讨论】:

  • 看了一下宏__COUNTER__?
  • __COUNTER__ 在这里不是一个选择,因为 1/ 每个翻译单元都是全局的,2/ 每次使用都会增加,3/ 这个宏只能有 1 个计数器...
  • #define MAX_COUNT 64 :( 即使在 C++03 中也有很多不错的选择。为什么在这里使用宏?
  • clang++3.4 和 g++4.8.2 之间的不同行为——clang++ 输出0 1,g++ 输出1 1。所以要么是编译器错误,要么是未指定/未定义的行为。
  • @Danvil haha​​... 在我拥有的一些模板元编程旁边,这可以称为“简单”。 致所有人:I posted a bug report in gcc bugzilla,让我们看看他们是否找到了一些东西(至少回答;))

标签: c++ templates


【解决方案1】:

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

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

【讨论】:

  • 是的,我认为这在某种程度上与两阶段查找有关,但是对于 dyp 示例,它似乎是关于一个独立名称被视为依赖的误报。但是,我认为 gcc 实现了两阶段名称查找(至少从 4.7 开始)?
  • 我认为你的权利,我误读了这篇文章。如果它是 GCC 中的错误,那么它可能与它的实现有关。它似乎选择延迟一些名称查找,直到模板实例化。选择何时执行查找的代码可能有问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-19
  • 2018-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多