0

I was playing around with templates, and ended up with a code like this:

#include <iostream>
#include <tuple>
#include <functional>

template<int... seq>
class A {

public:
    template<int... s>
    inline constexpr auto foo() const noexcept {
        return A<(std::get<s>(std::forward_as_tuple(seq...)))...>();
    }

};

template<int... seq>
class B {

public:
    template<int... s>
    inline constexpr auto foo() const noexcept {
        return B<(std::get<s>(std::forward_as_tuple(seq...)))...>();
    }

};

template<class A, class B>
class C {
public:
    template<int... s>
    inline constexpr auto bar() const noexcept {
        // I tried all of the following:
        constexpr A a;
        a.foo<s...>(); // error: parameter pack not expanded with ...
        return C<decltype(std::declval<A>().foo()), decltype(std::declval<B>().foo())>(); // works but no parameters are passed
        return C<decltype(std::declval<A>().foo<s...>()), decltype(std::declval<B>().foo<s...>())>(); // doesn't work
        return C<decltype(std::invoke(std::declval<A>().foo(), s...)), decltype(std::invoke(std::declval<B>().foo(), s...))>(); // doesn't work
    }
};

// I get the types of the objects, but I can't instantiate them
// because I don't have the parameters needed to create the object
template<template<int...> class A, template<int...> class B>
class D{};

// Similar attempt to D
// Not working because the parameter pack has to be at the end of the template parameter list
// But at the same time, I need two parameter packs
template<template<int...> class A, int... e1, template<int...> class B, int... e2>
class E {};

int main() {
    constexpr C<A<1, 2, 3>, B<4, 5, 6>> c;
    c.bar<2, 1, 0>();

    return 0;
}

Ideally, I'd like to get class C working, so that I can call the method bar with parameters as I'm passing them now, and somehow delegate them to the calls A::foo and B::foo, but I can't figure out what's going wrong exactly.

Does anyone know how could I achieve this? Or how can I do anything similar to it? I'm using C++17, and I need all of the objects evaluated at compile-time

Maki
  • 177
  • 7
  • 2
    There is too much going on in this code, but `a.foo();` must be `a.template foo();`. – HolyBlackCat Jan 25 '20 at 13:31
  • Could you please minimize your example and summarize what you want to do? – NutCracker Jan 25 '20 at 13:34
  • @HolyBlackCat, your comment solved my issue! I don't understand why though. Can you explain me why that line was wrong? – Maki Jan 25 '20 at 19:08
  • Also, apologies to both of you. I should've been more clear with what my question! It's probably not relevant anymore, but I made 2 variadic template classes (`A` and `B`), and I tried to pass them as template arguments to `C`. Then call the variadic template function `bar` from `C` that would create a new constexpr object of class `C` by calling it's default constructor and passing it elements received from calls to `foo` using `A` and `B`. The length of the comment is limited, so I hope that this makes at least some sense. – Maki Jan 25 '20 at 19:16
  • The linked question should explain it well. Basically, if the lhs of `.` depends on a template parameter, and rhs is a method template with template parameters specified, `template` must be used. That's because otherwise the compiler can't tell if you're calling a template method or comparing a bunch of objects for inequality, until substituting template parameters. And it wants to know that when it first sees the template, prior to substituting template parameters. – HolyBlackCat Jan 25 '20 at 22:21
  • Alright, I'll read through it! Also, thanks for the explanation – Maki Jan 26 '20 at 15:12

0 Answers0