问题描述
我在一些应用程序中使用编译时计数器,它是非常有用的。昨天我想用gcc编译一个程序(我以前使用msvc),并且计数器的行为在模板类中改变了(它不再在模板类中工作了)。
过于简化的代码:
//计数器可以容纳的最大值
#define MAX_COUNT 64
//用于存储一个数字作为结构的大小
template< unsigned int n> struct Count {bool data [n]; };
//用于重载函数,同时根据计数器值自动选择
//右边的值(见下面的代码)
template< int n> struct cn:public cn< n-1> {};
模板<> struct cn< 0> {};
struct Test
{
#define COUNT \
((sizeof(f(cn< MAX_COUNT + 1>()))/ sizeof(bool) - 1)
静态计数< 1> f(cn 1);
/ *
f(cn 65())将'调用'f(cn')并返回Count'与大小1
- > count = 0;
* /
static const int a = COUNT;
static Count< COUNT + 2> f(cn
/ *
现在计数< 2>定义f(cn 2),所以:
f(cn 65())将调用f(cn 2)并返回Count 2。与大小2
- > count = 1;
* /
static const int b = COUNT;
};
这个想法是使用函数重载,如果你测试上面的代码,( a == 0
和 b = = 1
)。
但是,如果struct Test
只需在声明之前添加 template< something>
,无需使用template参数),,我结束了 a == b == 1
。
这里是我的问题:
- 为什么会有这样的特定行为?
注意:我想要一个C ++ 03答案与旧编译器兼容即使我很想知道这个特定情况的规则是否改变了C ++ 11)
编辑:一些输出: p>
-
VC2010:
a = 0
b = 1
-
:
模板
a = 1
b = 1
-
(感谢dyp):
模板
a = 0
b = 1
编辑2
GCC似乎需要 c>作为附属名称,作为(感谢dyp)。我在gcc bugzilla 发布了一个错误报告。
这可能是C ++中的两阶段名称查找的属性。这是C ++ 03的一个特性,也存在于C ++ 11中。 LLVM项目对此功能做了并将其Clang编译器与GCC和Visual C ++进行比较。 GCC和Visual C ++不支持此功能,但Visual C ++有一个处理名称查找的方法,将允许依赖于两阶段查找的代码比在GCC上更频繁地工作。
编辑:我错误地阅读了这篇文章,GCC实现两阶段查找,但它可以选择延迟查找直到模板实例化。这似乎是一个错误在GCC虽然。
I use a compile-time counter in some applications, and it is really useful. Yesterday I wanted to compile a program with gcc (I was using msvc before), and the behavior of the counter changed in templated classes (it is not working anymore in template classes).
The overly simplified code:
// 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;
};
The idea is to use function overloading, and if you test the above code it will work perfectly (a == 0
and b == 1
).
However, if the struct Test
is made template (by just adding template<something>
before its declaration for example, no need to use the template parameter), the counter breaks and I end up with a == b == 1
. It also implies that it is impossible to increment the counter in these conditions.
So here are my questions :
- what template rules are at work here ?
- why that specific behavior ?
- do you have an idea of a work-around for the counter to actually work ?
Note: I would like a C++03 answer for compatibility with old compilers (even if I'm curious to know if rules for that specific case changed for C++11)
EDIT: Some outputs:
VC2010:
Templated a = 0 b = 1
Templated a = 1 b = 1
Clang 3.4 (thanks to dyp):
Templated a = 0 b = 1
EDIT 2
GCC seems to take Count
as a dependent name, as observable here (thanks to dyp). I posted a bug report in gcc bugzilla here.
This could be attributes to the two-phase name look-up in C++. This is a feature of C++03 that also exists in C++11. The LLVM project did an article on this feature and compare its Clang compiler to GCC and Visual C++. GCC and Visual C++ do not support this feature, but Visual C++ does have a method of handling name look-ups that will allow code dependent on the two-phase look-up to work more often than on GCC. It also allows code that is not valid C++ code to work as well according to the article.
EDIT: I misread the article, GCC does implement the two-phase look-up, but it can choose to delay the look-up until template instantiation. This does appear to be a bug in GCC though.
这篇关于模板与非模板类,跨编译器的不同行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!