1

Lets have following code which creates a tree of tuples and n-ary operator to aggregate values on particular level:

#include <tuple>

template<class O, class... I>
struct Compose
{
    using ITuple = std::tuple<I...>;

    Compose(O&& o, I&&... i) :
        o(std::forward<O>(o)),
        i(std::forward<I>(i)...)
    { }

    float operator ()(float x) const
    { /* return o(i1(x), i2(x), i3(x), ... ); */ }

    template<unsigned H1, unsigned H2, unsigned... Ts>
    decltype(auto) getI()
    { return std::get<H1>(i).getI<H2, Ts...>(); }

    template<unsigned H>
    decltype(auto) getI()
    { return std::get<H>(i); }

    O o;
    ITuple i;
};

template<class O, class... I>
Compose<O, I...>
make_compose(O&& o, I&&... i)
{ return Compose<O, I...>(std::forward<O>(o), std::forward<I>(i)...); }

struct Foo {
    Foo(float param) : p(param) { }

    float operator()(float v) const
    { return p * v; }

    float p;
};

int main()
{
    auto out = [](float x, float y) { return x + y; };
    auto c1 = make_compose(out, make_compose(out, Foo(2), Foo(3)), Foo(4));
    auto test1 = c1.getI<0, 1>();
    test1(1); // will return 3
    return 0;
}

I'm compiling with -std=C++14 and when i use GCC 6.4 it compiles fine. But with clang++ 3.9 it fails with error:

error: expression contains unexpanded parameter pack 'Ts'
{ return std::get<H1>(i).getI<H2, Ts...>(); }

Does anybody knows where is the real problem, beacuse it looks for me as obvious expansion of variadic parameter pack. Method getI() returns element in the tree by index on that level of tree.

I have found workaround for method getI<>() which passes the tuple element into a helper function doGetI() works in clang but looks messy:

template<unsigned... Ts>
decltype(auto) getI()
{ return doGetI<Compose2, Ts...>(*this); }

template<class T, unsigned H1, unsigned H2, unsigned... Ts>
decltype(auto) doGetI(T& t)
{ return doGetI<std::tuple_element_t<H1, typename T::ITuple>, H2, Ts...>(std::get<H1>(t._i)); }

template<class T, unsigned H>
decltype(auto) doGetI(T& t)
{ return std::get<H>(t._i); }
aschepler
  • 65,919
  • 8
  • 93
  • 144
Radek
  • 479
  • 3
  • 12

0 Answers0