As an exercise I am trying to write an array implementation using templates, but with a function pointer as a template parameter. This function would be called every time the array gets indexed.
template<typename T, int size>
using Array_fnIndex = void (*)(int index);
template<typename T, int size, typename Array_fnIndex<T, size> fnIndex>
struct Array {
T data[size];
T& operator[](int index) {
fnIndex(index);
return data[index];
}
};
// example index function
template<typename T, int size>
void checkIndex(int index) {
assert(index < size);
}
int main() {
Array<int, 10, checkIndex<int, 10>> a; // this works
Array<int, 10, checkIndex<int, 11>> b; // this also works, not what I want
Array<int, 10, checkIndex> c; // this doesn't work, but what I want
return 0;
}
The last Array declaration in the main function is what I would like, where the template parameters of checkIndex match the previous template parameters in Array. However this doesn't compile (using Microsoft compiler). I get the following error:
error C2440: 'specialization': cannot convert from 'void (__cdecl *)(uint)' to 'void (__cdecl *)(uint)'
note: None of the functions with this name in scope match the target type
Is there any way to get the desired result where the template parameters for the provided function get inferred from the other parameters?
May not be applicable in your real use case, but I suggest a callable object containing a function that does the check:
template<typename T, int size, typename fnIndex>
struct Array {
T data[size];
T& operator[](int index) {
fnIndex{}.template check<size>(index);
return data[index];
}
};
struct checkIndex {
template<int size>
void check(int index) {
assert(index < size);
}
};
int main() {
Array<int, 10, checkIndex> c;
return 0;
}
wandbox example
Let's analyze fnIndex{}.template check<size>(index):
fnIndex{} // make a temporary object of type `fnIndex`
.template check<size>(index) // call its `check` method using `size`
// as a template argument and `index` as
// as a function argument
The .template disambiguation syntax is required because the compiler does not know what check means - it could be a field and the line could be interpreted as:
fnIndex{}.check < size > (index)
where < is the less-than operator, > is the greater-than operator, and (index) is an expression.
Using .template tells the compiler that we want to invoke a template method.
Related
Why doesn't the below code compile? It says that S has to be const as one of the major errors.
template <int S>
class Array
{
int size;
int items [S];
public:
Array(void) :size(S){}
};
void main()
{
int S= 30;
Array <5+S> array;
}
Nontype template parameters must be constexpr, i.e., they have to be known at compile time. Hence, S must be declared as constexpr int.
template<size_t ROWS, size_t COLS>
void f(const array<array<int, COLS>, ROWS>& arr)
{
for(size_t r=0; r<ROWS; r++)
for(size_t c=0; c<COLS; c++)
//stuff
}
array<array<int, 2>, 3> arr {{{1,2},{3,4},{5,6}}};
f(arr);
This works but how? How does the template function figure out the row and col size? I'm not passing in size info during function call. I can see how template functions can figure out the type of the object being passed in, but in such a case I don't see how my ROWS and COLS are given values.
This question seeks understanding of this particular case with templates. The question isn't asking about vector or what other data structures exist.
The compiler is pattern-matching to make the call work. You're asking about a specific case but I'm not sure where your problem is in understanding so I will illustrate in steps
In the below example, I call f with i which is an int. The compiler deduces that T = int to get the call to work. You might say "how does it know int when I haven't passed that type information." but you have, just not explicitly in the template argument list:
template <typename T>
void f(T t) {
}
int main() {
int i = 1;
f(i); // deduces T = int
}
To go a step further, the compiler can deduce what T is for two different vector arguments. The calls to f below work because the compiler can match the std::vector pattern to the argument I am passing in:
template <typename T>
void f(std::vector<T> v) {
}
int main() {
std::vector<int> v1;
f(v1); // deduces T = int
std::vector<std::string> v2;
f(v2); // deduces T = std::string
}
In this next example, I create a class that only has one argument, which is a size_t and the compiler is still able to match against the Cls<I> pattern
template <std::size_t N>
class Cls { };
template <std::size_t I>
void f(Cls<I> v) {
}
int main() {
Cls<3> c1;
f(c1); // deduces I = 3
Cls<100> c2;
f(c2); // deduces I = 100
}
The std::array version works the same way, there is just another explicit template argument to std::array involved:
template <std::size_t I>
void f(std::array<int, I> v) {
}
int main() {
std::array<int, 3> a1;
f(a1); // deduces I = 3
std::array<int, 100> a2;
f(a2); // deduces I = 100
}
Impressively, even when there are multiple template arguments nested as your original example, the compiler can still look at the argument and match the pattern:
template<size_t ROWS, size_t COLS>
void f(std::array<std::array<int, COLS>, ROWS> arr) {
}
int main() {
std::array<std::array<int, 2>, 3> arr{};
f(arr); // deduces COLS = 2 and ROWS = 3 !!
}
Adding const and & in the above examples still works, the pattern is more complex but the compiler can still match it. What a time to be alive!
The size is embedded in the std::array. Because the size is part of std::array's type signature, that information is passed to f. Remember that std::array<int, 2> and std::array<int, 3> are completely different types that cannot be implicitly converted to each other.
Look at this example:
struct s77 {
char d[77];
};
struct s1 {
char d;
};
struct Foo: s77, s1 {
};
struct Off {
static const int v = std::size_t(static_cast<s1*>(static_cast<Foo*>(nullptr)+1)) - std::size_t(static_cast<Foo*>(nullptr)+1);
};
This code tries to put the offset of s1 in Foo into Off::v. This code compiles with GCC/clang (without any warnings), but fails to compile with VS2015/VS2017 (error C2131: expression did not evaluate to a constant)
Which compiler is correct?
Can I achieve this functionality in a standard conformant way? If it is not possible, is it possible to create a working solution which works with VS2015/VS2017? I'm willing to accept any working solution, even which has undefined behavior according to the standard (but happens to work with VS2015 and VS2017). Off::v must be a compile time constant.
My original problem is this: I have an own implementation of tuple, which is implemented with multiple inheritance (like clang's tuple). I'd like to create a compile-time constant "descriptor" for the tuple, which contains all of its members' offset in the tuple. This descriptor contains a function pointer for each tuple member too. If I'd create this descriptor by hand, it would look like this (for example):
struct Entry {
int offset;
void (*function)(void *member);
};
Entry descriptor[] = {
{ 0, &SomeType1::static_function },
{ 12, &SomeType2::static_function },
{ 20, &SomeType3::static_function }
};
The intention of this is that I could have a general function (which is not a template), which can use this descriptor to call a type-specific function on each tuple member:
void call(void *tuple, const Entry *entries, int n) {
for (int i=0; i<n; i++) {
entries[i].function(static_cast<char *>(tuple)+entries[i].offset);
}
}
(The reason of this solution instead of a templated call function is that call is actually a huge function in my real code, and entry[i].function calls cannot be factored out from it. I'd like to avoid massive code duplication.)
How about something like:
struct Entry {
void* (*data_member_getter)(void*);
void (*function)(void *member);
};
namespace details
{
template <std::size_t I, typename Tuple>
constexpr void* voidPGetter(void* tuple)
{
return &std::get<I>(*reinterpret_cast<Tuple*>(tuple));
}
template <typename Tuple, std::size_t I>
constexpr MakeEntry()
{
using type = std::tuple_element_t<I, Tuple>;
return { &voidPGetter<I, Tuple>, &type::static_function };
}
template <typename Tuple, std::size_t ... Is>
constexpr std::array<Entry, sizeof...(Is)>
ComputeEntryHelper(std::index_sequence<Is...>)
{
return {{MakeEntry<Is, Tuple>()...}};
}
}
template <typename Tuple>
constexpt auto ComputeEntry()
{
constexpr auto size = std::tuple_size<Tuple>::value;
return details::ComputeEntryHelper(std::make_index_sequence<size>());
}
And then
void call(void* tuple, const Entry* entries, int n) {
for (int i = 0; i != n; ++i) {
entries[i].function(entries[i].data_member_getter(tuple));
}
}
So instead of offset, having a function to get the data.
Given a template whose non-type parameter determines the size of a non-const int array member, how can I access the array elements by an integral index at compile time? I want the access to be done via the class template’s getter method at.
I figured since class templates must be instantiated before runtime, I can pass another non-type class template’s enum member value to the prior class’s at method to ensure the index argument is a compile-time constant.
I left the class template deliberate_error undefined to see if its arguments are computed at compile time and to view the compile-time results in the error messages.
template <unsigned int N>
struct compile_time_int {
enum {num = N};
};
template <unsigned int N>
struct array_wrapper {
int arr[N];
template <unsigned int Ind>
constexpr int const& at(compile_time_int<Ind> const& index) const {
return arr[index.num];
}
};
template <unsigned int> struct deliberate_error;
int main() {
compile_time_int<2> cti;
array_wrapper<3> aw;
aw.at(cti);
deliberate_error<cti.num> my_error1;
deliberate_error<aw.at(cti)> my_error2;
}
aw.at(cti); doesn’t give an error, so I thought that if I passed the same expression to deliberate_error instance my_error2, the compiler will display the value of arr[2] in the error message.
my_error1 causes g++ error: aggregate 'deliberate_error<2u> my_error1' has incomplete type and cannot be defined,
showing cti’s wrapped integral value 2. So, I thought if I passed the same cti to object aw's getter, and then pass the result to my_error2, I can get arr[2] in the error message. But instead, it prints:
error: the value of 'aw' is not usable in a constant expression
note: 'aw' was not declared 'constexpr'
note: in template argument for type 'unsigned int'
error: invalid type in declaration before ';'
So, I tried prepending constexpr to aw’s declaration, but that gives even more undesirable errors. What’s wrong here, and how can I fix it?
(Note that as far as I see, std::array with std::get already solves your problem.)
The main issue is that you need your instance aw to be constexpr and of course you need to initialize it with some values:
constexpr array_wrapper<3> aw = { 1, 2, 3 };
Regarding the function at, you can write it as a normal function but simply specify it as constexpr:
constexpr int const& at(int i) const {
return arr[i];
}
Then, aw.at(0) can be used as a constant expression: Live Demo
The advantage of this is that you can use this function in both compile-time and runtime expressions, with static and dynamic indexing, respectively.
If you really want it to be templated, you can either write it as a non-member like std::get<N> or as a class member, but use a template parameter of type int (or size_t or similar). That simplifies its definition (and you can get rid of your compile_time_int class template):
template<int Index>
constexpr int const& at() const {
return arr[Index];
}
Then, aw.at<0>() can be used as a constant expression: Live Demo
The advantage of the second method is that the index is guaranteed to be static, so we can use it in the function for static bound checking, which will not add any performance penalty. I don't know if this is possible with the first version.
Maybe just this:
template <unsigned int N>
struct array_wrapper
{
int arr[N];
};
template <unsigned int I, unsigned int N>
constexpr int & at(array_wrapper<N> & a)
{
static_assert(I < N, "static array index out of bounds");
return a.arr[I];
}
// add a "const" overload, too
Usage:
array_wrapper<10> x;
at<3>(x) = 42;
I want to implement a compile-time getter in a way to make its call more concise. I have a non-type (unsigned int N) class template foo, which recursively inherits from foo<N - 1>. Every foo has its own enum member called number, which is initialized to the value of its corresponding N. The base case is foo<0>. For example, a foo<5> object has 6 enums called number, valued 0 through 5. I want to implement a compile-time getter at, but it's not as easy as prepending a constexpr to the prototype:
template <unsigned int N>
struct foo : protected foo<N - 1> {
protected:
enum {number = N};
public:
constexpr int const& at(const unsigned int index) {
static_assert(index <= N, "out of range");
return this->foo<index>::number;
}
};
template <>
struct foo<0> {
protected:
enum {number = 0};
public:
constexpr int const& at(const unsigned int index) {
static_assert(index == 0, "out of range");
return this->number;
}
};
In g++ 4.8, I get several instances of the errors: error: 'index' is not a constant expression, among other things. The rest just follow suit. Even if all client code calls at with integer literals only, the getter won't compile. Why?
In any case, my solution was to implement a compile-time integer wrapper. It's simply a non-type (unsigned int N) class template ctint (short for compile-time int), whose enum member mem is initialized to its N:
template <unsigned int N>
struct ctint {
enum {mem = N};
};
So, replacing foo<N> and foo<0>'s getter methods, respectively, with:
template <unsigned int ind>
constexpr int const& at(ctint<ind> const& ctint_par) {
static_assert(ctint_par.mem <= N, "out of range");
return this->foo<ctint_par.mem>::number;
}
and
template <unsigned int ind>
constexpr int const& at(ctint<ind> const& ctint_par) {
static_assert(ctint_par.mem == 0, "out of range");
return this->number;
}
works:
int main() {
foo<5> f;
static_assert( f.at( ctint<4>{} ) != 4 , "equals 4");
}
but makes the function call verbose. I’d like an implementation that’s library-free aside from parts (e.g. <iostream>) that show something works but not help make it work. I’d like the getter to be able to optionally omit or have no <> syntax or spelling out of a type name in the call, but not necessarily in the prototype or definition. I don't want it to involve array[]s. If that’s impossible, I’d like to know the next-best way.