C++:迭代元组时忽略候选模板

C++: candidate template ignored when iterating over tuple

我正在尝试使用以下代码遍历元组:

template <std::size_t I = 0, typename... Ts>
    requires (I >= sizeof...(Ts))
static inline auto consume_all(std::tuple<Ts...>&&, auto) -> void {}

template <std::size_t I = 0, typename... Ts>
    requires (I < sizeof...(Ts))
static inline auto consume_all(std::tuple<Ts...>&& tup, auto f) -> void {
    f(std::get<I>(tup));
    consume_all<I + 1, Ts...>(tup, f);
}

据我所见,上面的定义并没有错。但是,当我尝试调用它时...:[=​​18=]

template <typename F, typename T>
concept unary = requires(F&& f, T&& t) {
    {
        f(t)
    } -> std::convertible_to<T>;
};

//...
//in struct definition:

    const std::tuple<Fs...> funcs;

//...
//in method definition:

                consume_all<Fs...>(
                        funcs,
                        [=, &t]<unary<T> F>(F f) {t = f(t);}
                );

...我收到一个编译时错误,指出两个模板都已被忽略:

No matching function for call to 'consume_all' in instantiation of member function 'chain<int, [function-typenames]>'
...
candidate template ignored: invalid explicitly-specified argument for template parameter 'I'
candidate template ignored: invalid explicitly-specified argument for template parameter 'I'

我看不出这个问题,因为 ... >= I... < I 的组合应该是包罗万象的。

编辑:

当指定 I (consume_all<0, Fs...>) 时,候选模板仍然被忽略,尽管现在它们会产生更具描述性的错误:

No matching function for call to 'consume_all'
...
candidate template ignored: //issue
deduced type 'tuple<...>' of 1st parameter does not match adjusted type
'const tuple<...>' of argument
[with I = 0, Ts = <(lambda)>, f:auto = (lambda)]

candidate template ignored: //rightfully
constraints not satisfied
[with I = 0, Ts = <(lambda)>, auto:3 = (lambda)]
because '0U >= sizeof...(Ts)' (0 >= 1) evaluated to false

你打电话给

consume_all<Fs...>

你不见了I。你需要

consume_all<0, Fs...>

在查看@Jarod42 的评论后,我找到了一种更好的方法来遍历元组,从而避开模板问题。

consume_all 定义为迭代函数不是正确的方法。

相反,consume_all 应该使用 std::apply(func, tup) 定义,它解析元组 tup 作为 func.

的参数

这现在将迭代元组的问题转换为迭代参数包的问题(这更容易)。

遍历参数包的元素:

template <typename F>
[[maybe_unused]] static inline void consume(F) {}
//^^^ Empty Base Case ^^^

template <typename F, typename Arg>
    requires std::invocable<F, Arg>
[[maybe_unused]] static inline void consume(F f, Arg arg) {
    f(arg);
}
//^^^ Single Arg Base Case ^^^

template <typename F, typename Arg, typename... Args>
    requires std::invocable<F, Arg>
static inline void consume(F f, Arg arg, Args... args) {
    f(arg);
    consume<F, Args...>(f, args...);
}
//^^^ Recursive General Case ^^^

现在我们已经定义了一个函数来使用参数包的每个元素,我们现在可以正确定义 consume_all

重新定义consume_all:

template <typename F, typename... Args>
[[maybe_unused]] static inline void consume_all(F f, std::tuple<Args...> tup) {
    std::apply(
            [&f](auto&&... args){
                consume(f, args...);
            },
            tup
    );
}

原题求解:

        consume_all(
                [&t]<unary<T> F>(F f) {t = f(t);},
                funcs
                );

我希望这对遇到类似问题的其他人有所帮助