我有以下代码:
#include <cstdlib>
#include <cstdio>
#include <atomic>
enum ATYPE { Undefined = 0, typeA, typeB, typeC };
template<ATYPE TYPE = Undefined>
struct Object
{
Object() { counter++; }
static std::atomic<int> counter;
};
template<ATYPE TYPE>
std::atomic<int> Object<TYPE>::counter(1);
template<ATYPE TYPE>
void test()
{
printf("in test\n");
Object<TYPE> o;
}
int main(int argc, char **argv)
{
test<typeA>();
printf("%d\n", Object<typeA>::counter.load());
Object<typeA>::counter.store(0);
for (int i = 0; i < sizeof(ATYPE); ++i) {
Object<static_cast<ATYPE>(i)>::counter.store(0);
}
return 0;
}
使用以下命令行编译时:
clang++ -o test -std=c++11 -stdlib=libc++ test.cpp
我收到以下错误:
test.cpp:32:20: error: non-type template argument is not a constant expression
Object<static_cast<ATYPE>(i)>::counter.store(0);
^~~~~~~~~~~~~~~~~~~~~
test.cpp:32:39: note: read of non-const variable 'i' is not allowed in a constant expression
Object<static_cast<ATYPE>(i)>::counter.store(0);
^
testray.cpp:31:18: note: declared here
for (int i = 0; i < sizeof(ATYPE); ++i) {
我理解我相信的问题。模板的论证需要是一个constexpr,而我显然不是。所以问题是,他们可以做些什么来改变这种方式。通过这个工作,我的意思是,我可以以某种方式有更好的方法从ATYPE中的每个类型重置这个模板类的静态计数器,而不仅仅是手动执行:
Object<Undefined>::counter.store(0);
Object<typeA>::counter.store(0);
...
当ATYPE包含多种类型时,这不是那么优雅和实用。
非常感谢您的帮助和建议。
答案 0 :(得分:7)
对于这类事情,递归通常是一个简单的解决方案:
#include <type_traits>
enum ATYPE { Undefined = 0, typeA, typeB, typeC, ATYPE_END };
void reset_Object_counter(std::integral_constant<ATYPE, ATYPE_END>)
{}
template < ATYPE n = Undefined >
void reset_Object_counter(std::integral_constant<ATYPE, n> p = {})
{
Object<p>::counter.store(0);
reset_Object_counter(std::integral_constant<ATYPE,
static_cast<ATYPE>(n+1)>{});
}
对于这种情况,AFAIK,功能模板专业化也起作用(而不是第一次重载):
template<>
void reset_Object_counter<ENUM_END>(std::integral_constant<ATYPE, ENUM_END>)
{}
无论哪种方式,仅使用reset_Object_counter();
将所有Object<...>
的计数器设置为0
。
这里的integral_constant
解决方案实际上有点过分,对于这个问题,非类型模板参数就足够了(因为函数模板特化可以取代结束递归的重载)。
template < ATYPE n = Undefined >
void reset_Object_counter()
{
Object<n>::counter.store(0);
reset_Object_counter<static_cast<ATYPE>(n+1)>();
}
template<>
void reset_Object_counter<ENUM_END>()
{}