C++ 嵌套参数包扩展

C++ 嵌套参数包扩展,c++,c++17,C++,C++17,请参阅下面的代码片段(矩阵乘法的实现)。是否可以使用类似于{((a[r][k]*b[k][c])+…)}的东西来简化它们 #include <array> #include <utility> template<typename T, size_t R, size_t C> using Matrix = std::array<std::array<T, C>, R>; template<typename A, typename

请参阅下面的代码片段(矩阵乘法的实现)。
是否可以使用类似于
{((a[r][k]*b[k][c])+…)}
的东西来简化它们

#include <array>
#include <utility>

template<typename T, size_t R, size_t C>
using Matrix = std::array<std::array<T, C>, R>;

template<typename A, typename B>
using mul_el_t = decltype(std::declval<A>()[0][0] * std::declval<B>()[0][0]);
使用
Apple LLVM 9.1.0版(clang-902.0.39.1)
编译失败,原因是:

[ 50%] Building CXX object CMakeFiles/main.cpp.o
main.cpp:38:51: error: pack expansion does not contain any unexpanded parameter packs
    return {{((a[R1][C1_R2] * b[C1_R2][C2]) + ...)...}...};
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
我认为失败是意料之中的,因为编译器不知道在每个扩展块中扩展哪个包(
R1
C2
C1\ur2
)。
在这种情况下,我如何提示编译器(注意,我可以使用任何编译器)?

根据文档,嵌套包扩展可以被视为一个迭代过程,从最里面的包扩展开始[3点]。每个包扩展都会扩展该包扩展包含的子表达式中的所有参数包

因此,在第一步之后,
{((a[R1][C1\ur2]*b[C1\ur2][C2])+…}成为
{(a[0][0]*b[0][0]+a[1][1]*b[1][1])}
R1/C2/C1\ur2
索引序列。所以接下来的两个包扩展没有什么可扩展的

原始解决方案 可以同时将每个参数包移动到所需的子表达式,将其携带的实际值保留在所需的位置。我们可以使用FP的模拟<代码>让。。。在
表达式中:

auto let = [](auto a, auto f) { return f(a); };
因此,最初的表达变成:

{let(R1, [&](auto r1) {
    return std::array<T, sizeof...(C2)>{let(C2, [&](auto c2) {
        return ((a[r1][C1_R2] * b[C1_R2][c2]) + ...);
    })...};
})...};
其中
ctor

template<typename H>
auto ctor()
{
    return [](auto... xs) { return H{xs...}; };
}
使用实用程序:

template<typename F>
auto curry(F f)
{
    return [=](auto... a) {
        return [=](auto... b) { return f(a..., b...); };
    };
};

template<typename F, typename G>
auto compose(F f, G g)
{
    return [=](auto... xs) {
        return f(g(xs...));
    };
};
foldr
,作为家庭作业

汇编说明
所有解决方案在生成相同二进制文件的意义上都是等效的。

gcc无法做到这一点,这是一个非常古老的错误。这个错误仍然存在于gcc8中:我可以使用任何其他编译器。问题是我不能想出好的代码来使用。请参考Q更新。
[ 50%] Building CXX object CMakeFiles/main.cpp.o
main.cpp:38:51: error: pack expansion does not contain any unexpanded parameter packs
    return {{((a[R1][C1_R2] * b[C1_R2][C2]) + ...)...}...};
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
auto let = [](auto a, auto f) { return f(a); };
{let(R1, [&](auto r1) {
    return std::array<T, sizeof...(C2)>{let(C2, [&](auto c2) {
        return ((a[r1][C1_R2] * b[C1_R2][c2]) + ...);
    })...};
})...};
template<typename H, typename F, typename T, T... I>
decltype(auto) repack(std::integer_sequence<T, I...>, H h, F f)
{
    return h(f(std::integral_constant<T, I>{})...);
}
template<typename T, size_t R1, size_t C1_R2, size_t C2>
Matrix<T, R1, C2> operator*(const Matrix<T, R1, C1_R2> &a, const Matrix<T, C1_R2, C2> &b)
{
    std::make_index_sequence<R1> r1{};
    std::make_index_sequence<C2> c2{};
    std::make_index_sequence<C1_R2> c1_r2{};

    return repack(r1, ctor<Matrix<T, R1, C2>>(), [&](auto r1) {
        return repack(c2, ctor<std::array<T, C2>>(), [&](auto c2) {
            return repack(c1_r2, sum, [&](auto c1_r2) {
                return a[r1][c1_r2] * b[c1_r2][c2];
            });
        });
    });
}
template<typename H>
auto ctor()
{
    return [](auto... xs) { return H{xs...}; };
}
template<typename T, size_t R1, size_t C1_R2, size_t C2>
Matrix<T, R1, C2> operator*(const Matrix<T, R1, C1_R2> &a, const Matrix<T, C1_R2, C2> &b)
{
    auto item = [&](auto r1, auto c2, auto c1_r2) { return a[r1][c1_r2] * b[c1_r2][c2]; };
    auto curried_repack = curry(POLY(repack));
    auto m = curried_repack(std::make_index_sequence<R1>{}, ctor<Matrix<T, R1, C2>>());
    auto r = curried_repack(std::make_index_sequence<C2>{}, ctor<std::array<T, C2>>());
    auto e = curried_repack(std::make_index_sequence<C1_R2>{}, sum);

    auto op = [](auto w, auto f) {
        return compose(w, curry(f));
    };
    return foldr(op, m, r, e, item)();
}
template<typename F>
auto curry(F f)
{
    return [=](auto... a) {
        return [=](auto... b) { return f(a..., b...); };
    };
};

template<typename F, typename G>
auto compose(F f, G g)
{
    return [=](auto... xs) {
        return f(g(xs...));
    };
};
#define POLY(f) ([](auto... a){ return f(a...); })