我想存储应该在编译期间和运行时使用的给定类型的整数。
到目前为止,我有以下内容:
template<typename T>
struct my_int { enum { result = -1 }; };
我专注于每种类型:
template<> struct my_int<a_type> { enum { result = 5 }; };
我可以在编译期间检查(当然这里的检查将是另一个编译时常量):
static_assert(my_int<a_type>::result == 5, "Bla");
问题: 只要专门化在同一名称空间中,这种方法就可以正常工作。但这是一个我想摆脱的不便。所以我希望能够在每个命名空间中使用它:
namespace foo {
template<> struct my_int<a_type> { enum { result = 5 }; };
}
namespace bar {
template<> struct my_int<b_type> { enum { result = 7 }; };
}
我有什么想法可以做到这一点?
如果真的需要,C ++ 11和boost对我的情况来说是好的。
更新:似乎我提供的信息很少。类型主要是enum classes
。如果您真的感兴趣,可以在这里看到真正的实现,http://www.codeduce.com/extra/enum_tools,下载zip并在标题行33,34中。
答案 0 :(得分:2)
如果您的用例可能,您可以在命名空间的基础上进行专业化,然后使用C ++ 11进行聚合,因为您提到它但可以不使用。
假设您有许多名称空间ns_1
到ns_k
,如下所示:
namespace ns_i {
template<class T> struct my_int: std::integral_constant<int, -1> {};
/*...*/
enum e_1 { /*...*/ };
template<> struct my_int<e_1>: std::integral_constant<int, 101> {};
/*...*/
enum e_n { /*...*/ };
template<> struct my_int<e_n>: std::integral_constant<int, 142> {};
/*...*/
}
我假设您已经有办法进行唯一编号。然后从所有命名空间聚合my_int
,如下所示:
namespace your_lib {
template<
class T,
template<class> class sources... /* any number of template classes,
each taking one type argument */
>
struct Union:
std::integral_constant<int, -1> {}; // default -1 for (empty template list)
template<
class T,
template<class> class source, // match first template
template<class> class sources... // match all but first template
>
struct Union<T, source, sources...>:
std::conditional<
source::value == -1,
union<T, sources...>, // recursively call union on all but first tempalte
source // or if there's a value in first, use it
> {};
template<class T> struct my_int :
Union<T, ns_1::my_int, /*...,*/ ns_k::my_int> {};
/* here you could use boost preprocessor to iterate over the namespaces
since you mentionned it */
}
答案 1 :(得分:2)
出于某种原因,我发现问题描述很容易被误解,但链接的代码清楚地表明了这一点。在C ++ 11中,它很简单:
#define SETUP_ENUM_LENGTH(enum_type, length) \
static constexpr int enum_length(enum_type*) { return length; }
和
for (int i = 0; i < enum_length((Enum*)0); ++i) {
在正确的地方。这是一个示例:
#include <iostream>
#include <functional>
#include <boost/preprocessor/variadic/size.hpp>
/**
* Macro to setup an enum completely.
* First parameter is the name, following are the states as plain text.
*/
#define DEF_ENUM(name, ...) \
enum class name : uint8_t { __VA_ARGS__ }; \
SETUP_ENUM_LENGTH(name, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__))
/**
* Once an enum class is defined, this macro makes the size publicly available.
* Needed by enum_array. Already included in DEF_ENUM.
*/
#define SETUP_ENUM_LENGTH(enum_type, length) \
static constexpr int enum_length(enum_type*) { return length; }
/**
* Function to iterate over all elements of an enum.
*/
template<typename Enum>
void enum_for_each(const std::function<void(Enum e)> &fct) {
for (int i = 0; i < enum_length((Enum*)0); ++i) {
fct(static_cast<Enum>(i));
}
}
namespace n {
DEF_ENUM(demo,u,v,w,x,y,z,a,b,c);
}
namespace m {
DEF_ENUM(demo,a=3,b=1,c=4,d=1,e=5);
}
using std::cout;
int main()
{
enum_for_each<n::demo>([](n::demo e) { cout<<int(e); });
cout<<'\n';
enum_for_each<m::demo>([](m::demo e) { cout<<int(e); });
cout<<'\n';
int ndemo[enum_length((n::demo*)0)];
int mdemo[enum_length((m::demo*)0)];
cout << sizeof ndemo << ' ' << sizeof mdemo << '\n';
}
作为旁注,static_cast<Enum>(i)
看起来很麻烦,它是否真的用m::demo
enum做了正确的事情?
要保留原始的模板化enum_length
用法,请从此处轻松使数组分配用法更加简洁,重命名函数enum_length_helper
然后
template<typename Enum>
struct enum_length {
enum result=enum_length_helper((Enum*)0);
};
答案 2 :(得分:1)
这是使用函数和ADL的解决方案:
#include <type_traits>
enum TypeInfo
{
Unknown = 0,
TypeA,
TypeB
};
template <TypeInfo x>
using TInfo = std::integral_constant<TypeInfo, x>;
template <class T>
TInfo<Unknown> TypeInfoFunc(T);
template <class T>
struct GetTypeInfo : decltype(TypeInfoFunc(std::declval<T>())){};
namespace a{
class A{};
TInfo<TypeA> TypeInfoFunc(A);
};
namespace b {
class B{};
TInfo<TypeB> TypeInfoFunc(B);
}
int main()
{
static_assert(GetTypeInfo<a::A>::value == TypeA, "");
static_assert(GetTypeInfo<b::B>::value == TypeB, "");
return 0;
}
使用ADL找到TypeInfoFunc
,这意味着它可以在与您专门用于的类相同的命名空间中定义。
修改强>
根据评论,我想我现在明白了一点。解决方案没有太大变化,只需简单地完成您的功能:
namespace a
{
struct A{};//Or whatever class you want to hold data about your type
A TypeInfoFunc(TInfo<TypeA>);
}
并将GetTypeInfo
更改为
template <TypeInfo x>
struct GetTypeInfo : decltype(TypeInfoFunc(TypeInfo<X>())) {};
这样您就可以调用GetTypeInfo<TypeA>
并访问(在本例中)类A
中的所有信息。
答案 3 :(得分:0)
如果您在类型本身中移动类型信息,则可以避免专门化结构的需要:
template <int V>
struct TypeInfo { enum { result = V, }; };
class yourClass : TypeInfo<2> //works better if you have an enum instad of number
{}
//...
static_assert(a_type::result == 2);
如果你这样做,你将永远不会遇到名称空间的问题,如果声明了类型,你将始终可以访问类型信息。