0

I am trying to find way to design a class template so that an int value is passed, and several function signatures as well as argument lists are dependent on this value.

Particularly, considering MyClass:

template <int N>
class MyClass {
    typedef SomeType<int, int, int, /* ... N times*/ > MyDepType;
    myFunction(std::string arg0, std::string  arg1, /* ...*/ std::string  argN) { /* do stuff */};
 public:
    MyClass() {
        someFunction(float arg0, float arg1, /* ...*/ float argN);   // <
        someOtherFunction(boost::bind(&MyClass::myFunction, this, _1, _2, /*...*/ _N));
    };
};

I'd like to be able to express both the private typedef call, the signature of myFunction and the argument list passed to external functions someFunction and someOtherFunction, which I can't edit/rewrite. Is there a way to achieve this, using the C++11 standard?

VolkerG
  • 148
  • 1
  • 2
  • 7
joaocandre
  • 1,621
  • 4
  • 25
  • 42
  • why not use [parameter pack](https://en.cppreference.com/w/cpp/language/parameter_pack)? – yaodav May 24 '20 at 18:06
  • Or maybe std::array? – kjpus May 24 '20 at 18:24
  • @yaodav Seems that might help, I'll look into it; @kjpus I thought about that, but `someFunction` and `someOtherFunction` take each argument individually and since they are not my code, can't change their signature. – joaocandre May 24 '20 at 18:35
  • I think my previous answer answers you perfectly unless you have misunderstood something. – asmmo May 24 '20 at 21:34
  • I'm still trying to understand how any of these answers check all of the requirements. For once, none of them consider how to pass the argument order to `boost::bind`, which is honestly my main issue. Then again, I'll admit I don't have much experience with this kind of static programming. – joaocandre May 24 '20 at 22:19

2 Answers2

0

You could use a trick like in this post (Produce std::tuple of same type in compile time given its length by a template argument) to produce a tuple of N elements.

template <int N, typename T> 
struct tuple_n_impl {
    template <typename... Ts> 
    using type = typename tuple_n_impl<N - 1, T>::template type<T, Ts...>;
};

template <typename T> 
struct tuple_n_impl<0, T> {
    template <typename... Ts> 
    using type = std::tuple<Ts...>;
};

template <int N, typename T>
using tuple_n = typename tuple_n_impl<N, T>::template type<>;

template <int N>
class MyClass {
    void int_function(tuple_n<N, int>&& ints);
    void float_function(tuple_n<N, float>&& floats);

    template <typename T> 
    void any_function(tuple_n<N, T>&& elements);
};
Jazzwave06
  • 1,883
  • 1
  • 11
  • 19
  • Neat solution (I'll be saving that tuple trick for later), but this requires the functions arguments to be tuples right? I can't change the function's prototypes. – joaocandre May 24 '20 at 20:38
  • Not really, you could do it with a parameter pack + the tuple to access the indices. Or you could use an array. you could do something like `template void int_function(Ts&&... elements) { int_function(std::make_tuple(std::forward(elements)...); }`. This solution does require two methods for each implementation though. – Jazzwave06 May 24 '20 at 20:42
0

You might use std::index_sequence (C++14, but implementation in C++11 can be found on SO):

template <std::size_t, typename T>
using always_t = T;

template <std::size_t ... Is>
class MyClassImpl {
    using MyDepType = SomeType<always_t<Is, int>...>;
    void myFunction(always_t<Is, std::string>... args) { /* do stuff */}
 public:
    MyClass() {
        void someFunction(always_t<Is, std::float>... args);
        someOtherFunction([this](always_t<Is, const std::string&>... args) {
            return myFunction(args...);
        });

        // 
        std::array<std::string, sizeof...(Is)> strings = {std::to_string(Is)...};
        myFunction(strings[Is]...);
    };
};

template <std::size_t N>
using MyClass = MyClassImpl<std::make_index_sequence<N>>;
Jarod42
  • 203,559
  • 14
  • 181
  • 302