#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*
U
can be deduced solely from the argument of the T1
constructorV...
can be deduced solely from the argument of the T1
constructorN
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);
}
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