Constexpr counter that works on GCC 8, and is not restricted to namespace scope

后端 未结 2 836
臣服心动
臣服心动 2021-01-05 09:50

I\'m trying to learn some arcane stateful template metaprogramming tricks.
(Here\'s why I want to learn it. Unfortunately this library doesn\'t work on GCC

2条回答
  •  广开言路
    2021-01-05 10:19

    As I didn't find fully working version, I improved @anthony-williams solution by adding custom start and step value, and also added some compatibility with MVSC, clang and gcc (thanx to @segfault comment).
    I hope it may me helpful.
    code tests

    namespace detail
    {
    
    template  class Flag
    {
        struct Dummy
        {
            constexpr Dummy()
            {
            }
            friend constexpr void adl_flag(Dummy);
        };
    
        template 
        struct Writer
        {
            friend constexpr void adl_flag(Dummy)
            {
            }
        };
    
        template 
        static constexpr bool Check(int)
        {
            return true;
        }
    
        template 
        static constexpr bool Check(short)
        {
            return false;
        }
    
    public:
    
        template (0)>
        static constexpr bool ReadSet()
        {
            Writer tmp{};
            (void)tmp;
            return Value;
        }
    
        template (0)>
        static constexpr int Read()
        {
            return Value;
        }
    };
    
    template 
    struct Tag
    {
    
        constexpr int value() const noexcept
        {
            return I;
        }
    };
    
    template
    struct Checker
    {
        static constexpr int currentval() noexcept
        {
            return N;
        }
    };
    
    template
    struct CheckerWrapper
    {
        template>{}.Read(), int M = Checker{}.currentval() >
        static constexpr int currentval()
        {
            return M;
        }
    };
    
    template
    struct Checker
    {
        template{}.currentval() >
        static constexpr int currentval() noexcept
        {
            return M;
        }
    };
    
    template>{}.ReadSet() >
    struct Next
    {
        static constexpr int value() noexcept
        {
            return N;
        }
    };
    
    }
    
    template 
    class constexpr_counter
    {
    public:
        template {}.currentval()>
        static constexpr int next()
        {
            return detail::Next{}.value();
        }
    };
    

    examples:

    using counter_A_0_1 = constexpr_counter;
    constexpr int a0 = counter_A_0_1::next();
    constexpr int a1 = counter_A_0_1::next();
    constexpr int a2 = counter_A_0_1::next();
    static_assert(a0 == 0);
    static_assert(a1 == 1);
    static_assert(a2 == 2);
    
    using counter_B_0_1 = constexpr_counter;
    constexpr int b0 = counter_B_0_1::next();
    constexpr int b1 = counter_B_0_1::next();
    constexpr int b2 = counter_B_0_1::next();
    static_assert(b0 == 0);
    static_assert(b1 == 1);
    static_assert(b2 == 2);
    
    using counter_C_2_1 = constexpr_counter;
    constexpr int c0 = counter_C_2_1::next();
    constexpr int c1 = counter_C_2_1::next();
    constexpr int c2 = counter_C_2_1::next();
    static_assert(c0 == 2);
    static_assert(c1 == 3);
    static_assert(c2 == 4);
    
    using counter_D_4_1 = constexpr_counter;
    constexpr int d0 = counter_D_4_1::next();
    constexpr int d1 = counter_D_4_1::next();
    constexpr int d2 = counter_D_4_1::next();
    static_assert(d0 == 4);
    static_assert(d1 == 5);
    static_assert(d2 == 6);
    
    using counter_E_5_3 = constexpr_counter;
    constexpr int e0 = counter_E_5_3::next();
    constexpr int e1 = counter_E_5_3::next();
    constexpr int e2 = counter_E_5_3::next();
    static_assert(e0 == 5);
    static_assert(e1 == 8);
    static_assert(e2 == 11);
    
    using counter_F_2_m3 = constexpr_counter;
    constexpr int f0 = counter_F_2_m3::next();
    constexpr int f1 = counter_F_2_m3::next();
    constexpr int f2 = counter_F_2_m3::next();
    static_assert(f0 == 2);
    static_assert(f1 == -1);
    static_assert(f2 == -4);
    

提交回复
热议问题