Home > Software engineering >  simplify template interface, remove redundant typenames
simplify template interface, remove redundant typenames

Time:06-07

#include <cstddef>
#include <utility>

template <size_t N, typename... V>
struct T {
    int test(size_t n, const char** ss) {
        if (N > n)
            return 1;
        return []<size_t... I>(const char* ss[N], std::index_sequence<I...>) {
            return test_impl(ss[I]...);
        }(ss, std::make_index_sequence<N>{});
    }

    // Ideally this would be templated, solving my problem:
    // i.e. move "typename... V" from the struct to this function.
    virtual int test_impl(V...) = 0;
};

template <typename U, size_t N, typename... V>
struct T1 : T<N, V...> {
    U value;
    int (*tester)(U*, V...);

    int test_impl(V... v) {
        return tester(&value, v...);
    }

    // virtual is not an aggregate
    T1(U value, int (*tester)(U*, V...))
        : value{value}, tester{tester}
        {};
};

int test1(int* v, const char* s1, const char* s2) {
    return 1;
}

template <typename... V>
int test2(int* v, V... ss) {
    return 1;
}

C is very good at deducing template function parameters from function arguments, but virtual function templates are not allowed. I am forced to move the function template parameters to the struct template, and find that C is not good at deducing template struct parameters from member variables. In the end I am forced to specify redundant information to the template which makes the T1/T interface difficult to use? How can I fix this?

For example, here we know that:

  • sizeof...(V) == N
  • decltype(V) must be const char*
  • template parameter U can be deduced solely from the argument of the T1 constructor
  • template parameter V... can be deduced solely from the argument of the T1 constructor
  • from which it follows that template parameter N can be deduced solely from the argument of the T1 constructor.
int main() {
    // The '2' and the 'const char*'... are redundant
    T1 a = T1<int, 2, const char*, const char*>(10, test1);
    T1 b = T1<int, 2, const char*, const char*>(10, test2);

    // There is enough information here to deduce the values
    T1 c = T1(10, test1);

    // There is enough information here to deduce the values
    T1 d = T1<..., 2, ...>(10, test2);
}

CodePudding user response:

sizeof...(V) == N

No, the compiler doesn't know it. (Take a look at the error messages)

Since you have this prequisite, you don't have to have the template parameter N.

template <typename... V>
struct T {
    
    int test(size_t n, const char** ss) {
        constexpr int N = sizeof...(V);
        if (N > n)
            return 1;
        return []<size_t... I>(const char* ss[N], std::index_sequence<I...>) {
            return test_impl(ss[I]...);
        }(ss, std::make_index_sequence<N>{});
    }

    // Ideally this would be templated, solving my problem:
    // i.e. move "typename... V" from the struct to this function.
    virtual int test_impl(V...) = 0;
};

See online demo

  • Related