如何在C++11/14中用constexpr生成pair<char,char>的std::array常量
C++14 实现方案
问题核心是C11/14中std::pair<char, char>的构造函数并非constexpr,同时std::array的编译期初始化支持有限。以下是两种可行的C14实现:
方案1:自定义constexpr Pair替代
#include <array> // 自定义支持编译期构造的Pair结构 template<typename T1, typename T2> struct ConstexprPair { T1 first; T2 second; constexpr ConstexprPair(T1 f, T2 s) : first(f), second(s) {} }; // 编译期生成完整牌组 constexpr auto make_deck() { std::array<ConstexprPair<char, char>, 52> deck{}; const char suits[] = {'S', 'H', 'D', 'C'}; const char ranks[] = {'A', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K'}; int idx = 0; for (int s = 0; s < 4; ++s) { for (int r = 0; r < 13; ++r) { deck[idx++] = ConstexprPair<char, char>{suits[s], ranks[r]}; } } return deck; } // 编译期初始化的全局牌组常量 constexpr auto deck = make_deck();
方案2:利用索引序列生成元素(无需自定义Pair)
借助C++14的std::index_sequence,通过聚合初始化构造std::pair(编译期聚合初始化不受构造函数非constexpr限制):
#include <array> #include <utility> using Card = std::pair<char, char>; template<std::size_t... Idx> constexpr std::array<Card, 52> make_deck_impl(std::index_sequence<Idx...>) { const char suits[] = {'S', 'H', 'D', 'C'}; const char ranks[] = {'A', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K'}; return {{ {suits[Idx/13], ranks[Idx%13]}... }}; } constexpr std::array<Card, 52> make_deck() { return make_deck_impl(std::make_index_sequence<52>{}); } constexpr auto deck = make_deck();
C++11 实现方案
C++11无std::index_sequence,且constexpr函数不允许循环,需用递归模板完成编译期初始化:
#include <array> #include <utility> using Card = std::pair<char, char>; // 递归模板生成单个牌元素 template<std::size_t N> struct DeckGenerator { static constexpr Card get() { const char suits[] = {'S', 'H', 'D', 'C'}; const char ranks[] = {'A', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K'}; return {suits[N/13], ranks[N%13]}; } static constexpr void fill(std::array<Card, 52>& arr) { DeckGenerator<N-1>::fill(arr); arr[N] = get(); } }; // 递归终止条件 template<> struct DeckGenerator<0> { static constexpr Card get() { return {'S', 'A'}; } static constexpr void fill(std::array<Card, 52>& arr) { arr[0] = get(); } }; constexpr std::array<Card, 52> make_deck() { std::array<Card, 52> arr{}; DeckGenerator<51>::fill(arr); return arr; } constexpr auto deck = make_deck();
代码优化建议
- 增强类型安全:用枚举替代char表示花色和点数,避免无效值:
enum class Suit { Spade, Heart, Diamond, Club }; enum class Rank { Ace, Two, Three, ..., King }; struct Card { Suit suit; Rank rank; }; - 消除魔法数字:将52、4、13等常量定义为
constexpr变量,比如constexpr std::size_t DECK_SIZE = 52;,提升可读性和可维护性。 - 优先选择简洁实现:C++14及以上版本优先用constexpr函数+循环的写法,模板元编程仅在必要场景使用。
- 复用std::pair:C++14中可通过聚合初始化在constexpr函数里构造
std::pair,无需自定义结构,如方案2所示。
内容的提问来源于stack exchange,提问作者Nemexia
相关产品推荐
相关产品推荐

