typedef enum colors {
MIN_COLOR,
RED = MIN_COLOR,
GREEN,
MAX_COLOR
} colors;
template< colors C >
struct MapEntry {
std::string s;
MapEntry(std::string s_):s(s_) {}
};
void do_in_order() {}
template<typename F0, typename... Fs>
void do_in_order(F0&& f0, Fs&&... fs) {
std::forward<F0>(f0)();
do_in_order(std::forward<Fs>(fs)...);
}
struct MapInit {
std::map< std::string, color > retval;
operator std::map< std::string, color >() {
return std::move(retval);
}
template<colors C>
void AddToMap(MapEntry<C>&& ent) {
retval.insert(std::make_pair(std::move(end.s), C));
}
template< typename... Entries >
MapInit(Entries&& entries) {
do_in_order([&](){ AddToMap(entries); }...);
}
};
template<typename... Entries>
MapInit mapInit(Entries&&... entries) {
return MapInit(std::forward<Entries>(entries)...);
}
const std::map<std::string, colors> = mapInit(MapEntry<RED>("red"), MapEntry<GREEN>("green"));
,讓你從編譯時color
構建std::map
和運行時string
數據的C++ 11的方式。
接下來在「列表MapEntry<colors>
列表colors
」元功能下。
template<colors... Cs>
struct color_list {};
template<typename... Ts>
struct type_list {};
template<typename MapEnt>
struct extract_color;
template<colors C>
struct extract_color<MapEntry<C>> {
enum {value=C};
};
template<typename Entries>
struct extract_colors;
template<typename... MapEntries>
struct extract_colors<type_list<MapEntries...>> {
typedef color_list< ((colors)extract_colors<MapEntries>::value)... > type;
};
對該列表進行排序。檢測重複 - 如果有的話,你搞砸了。
編譯時排序比其餘部分和100多行代碼更難。如果你不介意太多,我會放棄它! Here is a compile time merge sort I wrote in the past to answer a stack overflow question,它可以使用相對簡單的適應性(它使用值對類型進行排序,在這種情況下我們直接對編譯時間值列表進行排序)。
// takes a sorted list of type L<T...>, returns true if there are adjacent equal
// elements:
template<typename clist, typename=void>
struct any_duplicates:std::false_type {};
template<typename T, template<T...>class L, T t0, T t1, T... ts>
struct any_duplicates< L<t0, t1, ts...>, typename std::enable_if<t0==t1>::type>:
std::true_type {};
template<typename T, template<T...>class L, T t0, T t1, T... ts>
struct any_duplicates< L<t0, t1, ts...>, typename std::enable_if<t0!=t1>::type>:
any_duplicates< L<t1, ts...> > {};
檢測的colors
(即,<MIN_COLOR
或>=MAX_COLOR
)在有效範圍之外的元素。如果是這樣,你搞砸了。
template<typename List>
struct min_max;
template<typename T, template<T...>class L, T t0>
struct min_max {
enum {
min = t0,
max = t1,
};
};
template<typename T, template<T...>class L, T t0, T t1, T... ts>
struct min_max {
typedef min_max<L<t1, ts...>> rest_of_list;
enum {
rest_min = rest_of_list::min,
rest_max = rest_of_list::max,
min = (rest_min < t0):rest_min:t0,
max = (rest_max > t0):rest_max:t0,
};
};
template< typename T, T min, T max, typename List >
struct bounded: std::integral_constant< bool,
(min_max<List>::min >= min) && (min_max<List>::max < max)
> {};
算多少元素還有 - 應該有MAX_COLOR
元素。如果沒有,你搞砸了。
template<typename List>
struct element_count;
template<typename T, template<T...>L, T... ts>
struct element_count<L<ts...>>:std::integral_constant< std::size_t, sizeof...(ts) > {};
如果這些都沒有發生,那麼您必須初始化它們中的每一個。
唯一缺失的是你可能已經關閉了,並且對於兩個值使用相同的string
。由於編譯時間string
是一個痛苦,只需在運行時檢查它(在初始化之後,map
中的條目數等於colors
的數目)。
在C++ 03中這樣做會更困難。你缺乏variardic模板,所以你最終不得不僞造它們。這是一個痛苦。 mpl
可能可以幫助您。
2012年11月MSVC CTP編譯器更新中提供了Variardic模板。
這是一個沒有重複檢查和沒有邊界檢查的玩具示例(它只是檢查地圖項的數量是否匹配);
#include <cstddef>
#include <utility>
#include <string>
#include <map>
enum TestEnum {
BeginVal = 0,
One = BeginVal,
Two,
Three,
EndVal
};
template<TestEnum e>
struct MapEntry {
enum { val = e };
std::string s;
MapEntry(std::string s_):s(s_) {}
};
void do_in_order() {}
template<typename F0, typename... Fs>
void do_in_order(F0&& f0, Fs&&... fs) {
std::forward<F0>(f0)();
do_in_order(std::forward<Fs>(fs)...);
}
template<typename... MapEntries>
struct count_entries:std::integral_constant< std::size_t, sizeof...(MapEntries) > {};
// should also detect duplicates and check the range of the values:
template<typename... MapEntries>
struct caught_them_all:
std::integral_constant<
bool,
count_entries<MapEntries...>::value == (TestEnum::EndVal-TestEnum::BeginVal)
>
{};
struct BuildMap {
typedef std::map<std::string, TestEnum> result_map;
mutable result_map val;
operator result_map() const {
return std::move(val);
}
template<typename... MapEntries>
BuildMap(MapEntries&&... entries) {
static_assert(caught_them_all<MapEntries...>::value, "Missing enum value");
bool _[] = { ((val[ entries.s ] = TestEnum(MapEntries::val)), false)... };
}
};
std::map< std::string, TestEnum > bob = BuildMap(
MapEntry<One>("One")
,MapEntry<Two>("Two")
#if 0
,MapEntry<Three>("Three")
#endif
);
int main() {}
更換#if 0
與#if 1
看它編譯。 Live link如果你想玩。
你在出廠前測試你的代碼,對不對?因此,運行時檢查足以確保它能夠工作,您不覺得嗎? –
如果您爲每個值添加一個「case」並且您沒有「默認」分支,那麼如果您錯過枚舉值,那麼我知道的唯一語言構造會警告您。我想這意味着你將需要一個宏,但我遠沒有建議任何具體的:) –
我同意運行時測試應該足夠了,我也知道有關警告。我想我只是想弄清楚這可以推出多遠 – FKaria