代码之家  ›  专栏  ›  技术社区  ›  Amos

为constexpr模板参数显式指定的参数无效

  •  1
  • Amos  · 技术社区  · 6 年前

    我有一个 static_loop 像这样构造

    template <std::size_t n, typename F> void static_loop(F&& f) {
        static_assert(n <= 8 && "static loop size should <= 8");
        if constexpr (n >= 8)
            f(std::integral_constant<size_t, n - 8>());
        if constexpr (n >= 7)
            f(std::integral_constant<size_t, n - 7>());
        if constexpr (n >= 6)
            f(std::integral_constant<size_t, n - 6>());
        if constexpr (n >= 5)
            f(std::integral_constant<size_t, n - 5>());
        if constexpr (n >= 4)
            f(std::integral_constant<size_t, n - 4>());
        if constexpr (n >= 3)
            f(std::integral_constant<size_t, n - 3>());
        if constexpr (n >= 2)
            f(std::integral_constant<size_t, n - 2>());
        if constexpr (n >= 1)
            f(std::integral_constant<size_t, n - 1>());
    }
    
    
    template <typename T> constexpr size_t tupleSize(T) { return tuple_size_v<T>; }
    struct A {
        int a;
        int b;
        void run() {
            auto ab = std::make_tuple(std::ref(a), std::ref(b));
            static_loop<tupleSize(ab)>([&](auto i) { std::get<i>(ab) = i; });
            std::cout << a << " " << b << std::endl;
        }
    };
    

    但是,它无法在上面列出的元组上迭代。

    live godbolt example

    2 回复  |  直到 6 年前
        1
  •  0
  •   max66    6 年前

    建议:尝试

    // .........VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
    static_loop<std::tuple_size_v<decltype(ab)>>([&](auto i) { std::get<i>(ab) = i; });
    

    我的意思是…你不能用 ab (作为值),在常量表达式中,因为 抗体 未定义 constexpr .

    你不能定义它 常量表达式 因为它是用 std::ref() 那不是 常量表达式 .

    但你不感兴趣 抗体 作为获取其类型大小的值;您只对 抗体 打字,这样你就可以通过了 decltype(ab) .

    --编辑——

    非主题建议。

    而不是 static_loop() ,您可以使用基于 std::index_sequence (模板折叠,可从C++ 17开始)。

    我的意思是…如果定义了 run_1() 函数(与 run_1_helper() 助手)如下

    template <typename F, typename ... Ts, std::size_t ... Is>
    void run_1_helper (F const & f, std::tuple<Ts...> & t, std::index_sequence<Is...> const)
     { (f(std::get<Is>(t), Is), ...); }
    
    template <typename F, typename ... Ts>
    void run_1 (F const & f, std::tuple<Ts...> & t)
     { run_1_helper(f, t, std::index_sequence_for<Ts...>{}); }
    

    你可以写 A 如下

    struct A {
        int a;
        int b;
        void run() {
            auto ab = std::make_tuple(std::ref(a), std::ref(b));
            run_1([](auto & v, auto i){ v = i; }, ab);
            std::cout << a << " " << b << std::endl;
        }
    };
    

    或者,也许更好,简单地使用 std::apply() ,如下

    struct A {
        int a;
        int b;
        void run() {
            auto ab = std::make_tuple(std::ref(a), std::ref(b));
            int i { -1 };
            std::apply([&](auto & ... vs){ ((vs = ++i), ...); }, ab);
            std::cout << a << " " << b << std::endl;
        }
    };
    
        2
  •  0
  •   Barry    6 年前

    变化

    template <typename T>
    constexpr size_t tupleSize(T) { return tuple_size_v<T>; }
    

    到:

    template <typename T>
    constexpr size_t tupleSize(T const&) { return tuple_size_v<T>; }
    

    也就是说,通过引用const而不是通过value来获取参数。实际上,您正试图在常量表达式中复制一个非constexpr元组——这不起作用。引用是很好的,因为您实际上并没有阅读元组。

    推荐文章