Class template with array or vector arguments - c++

I need to write a class template definition with two template parameters (type , functor) and two template arguments (array/std::vector , int) that can execute the following code:
const char* message= "Message";
const transform<char, firstFunctor> first(message, lengthOfMessage);
transform_view<int, secondFunctor> second(intArray, intSize);
transform<double, thirdFunctor> third(doubleArray, doubleSize);
The type of the array/ vector has to match the type of the first template parameter.
I tried some variations like this:
template <typename A, typename B>
class transform
{
public:
transform<A, B>(A[], B) {...};
}
But I could not get the constructor's first parameter to match all of the three types.
Any advice is appreciated, thanks!

you wrote the definition of the constructor incorrectly.
transform<A, B>(A[], B) {...}; you will pass a vector, so why did you write A[] as a parameter type?
You need something like the following
#include <iostream>
template <typename T>
struct functor{
void operator()(const T array [], size_t sze) {
for (int i{}; i < sze; ++i) {
std::cout << array[i] << " ";
}
std::cout << "\n";
}
};
template<typename T, typename Function>
class transform {
const T* array;
size_t sze;
Function functor{};
public:
transform(const T array [], size_t sze):array{array}, sze{sze}{
functor(array, sze);
}
};
template< typename T, typename E>
using transform_view = transform<T, E>;
int main()
{
using firstFunctor = functor<char>;
using secondFunctor = functor<int>;
using thirdFunctor = functor<double>;
const char *message = "Message";
size_t lengthOfMessage = 7;
int intArray[] = {1, 3};
size_t intSize = 2;
double doubleArray[] = {1.4, 3.2};
size_t doubleSize = 2;
//The given three lines
const transform<char, firstFunctor> first(message, lengthOfMessage);
transform_view<int, secondFunctor> second(intArray, intSize);
transform<double, thirdFunctor> third(doubleArray, doubleSize);
}
The output
M e s s a g e
1 3
1.4 3.2

From what I understand, the problem is the first parameter being the array in the template.
Try the following constructor:
transform(A* arr, B el){
//now here is a tricky part, because there is a very big difference
//between a char*, and an int/double/unsigned/float/... *.
}
If you have an array of the type A in the class and want to change it to the one passed:
private:
A* my_array;
you can try sth like this:
if(dynamic_cast<char*>(arr)) //if arr is of type char* {
if (this->my_array != nullptr) delete my_array; //not needed if in a basic constructor...
size_t len = strlen(arr);
my_array = new char [len + 1];
strcpy(this->my_array, arr); //(destination, source)
my_array[len] = '\0';
}
else //if it is a numeric array
{
this->my_array = arr;
//redirecting the pointers in enough
}
Oh and if you are on Visual Studio, strcpy will work if you write
'#pragma warning (disable: 4996)' at the top of the file.
Otherwise it marks it as unsafe and suggests strncpy, strcpy_s, ...

Related

Cast custom struct to another template type

template <typename T>
struct Colordata
{
public:
T *data;
unsigned long size;
unsigned long length;
template <size_t N>
Colordata(T (&arr)[N])
{
length = N;
size = sizeof(arr);
T dataArr[length];
for (int i = 0; i < N; i++)
{
dataArr[i] = arr[i];
}
data = dataArr;
}
template <typename TCast>
operator TCast() const
{
TCast dataCastTmp[length];
for (int i = 0; i < length; i++)
{
dataCastTmp[i] = (TCast)data[i];
}
return Colordata<TCast>(dataCastTmp);
}
};
int main(int argc, char const *argv[])
{
int arr[] = {12, 434, 54};
auto a = Colordata<int>(arr);
auto b = (float)a;
return 0;
}
When I tried to convert Struct<typename> to Struct<another typename> another typename doesn't exist. I think so 'cos I get error in the compiler log:
no matching function for call to «Colordata::Colordata(float [((const Colordata*)this)->Colordata::length])»
Is there any way to casting template struct to template struct?
There are many problems with this code, but the one you asked about is happening because of the signature of the conversion operator:
template <typename TCast>
operator TCast() const
If you try to cast to a Colordata<float> then TCast will be the type Colordata<float>, and not float as the implementation assumes.
The solution is to only allow conversions to other Colordata instantiations:
template <typename TCast>
operator Colordata<TCast>() const
Now TCast will be float as desired, and you're one step closer to correct code.
The other problems are the use of variable-length arrays (not supported in C++), and storing pointers to local variables that outlive their scope leading to undefined behaviour. Use std::vector to make life easier and safer.

How to pass a dynamic object of the type array to a function?

I want to pass a dynamic size standard and of typename type array to a function.
I can't figure out how to do it. Why can't I just accept a reference to the object array?
The code I tried:
#include <iostream>
#include <array>
using namespace std;
template <typename T>
void showArrays(void *myArrayPointer, int size, T type) {
array<T, size> myArray = myArrayPointer;
for (int i = 0; i < size; i++) {
cout << myArray.at(i) << " \n";
}
}
int main()
{
array<int,6> myArray = { 1,2,3,4,5,6 };
cout << "The array is \n";
showArrays(&myArray,6,0);
return 0;
}
But I get expected compile-time constant expression for the Size still.
My function header is also not very pretty. But I couldn't figure out a way to have the size dynamic without passing a generic pointer or creating a template of the class array where the size is an attribute.
There is no reason to use a void* here at all. The type of the elements and size of a std::array are known at compile time and you can capture those using a template.
template<typename T, std::size_t N>
void print_arry(const std::array<T, N>& arr)
{
for (const auto& e : arr)
std::cout << e << "\n";
}
Will capture any std::array and print its elements as long as they have an overloaded operator <<. You can also use T as the element type and N as the size of the array inside the function which lets you write a accumulate function like
template<typename T, std::size_t N>
T print_arry(const std::array<T, N>& arr)
{
if (N == 0)
return 0;
T accum = arr[0];
for (std::size_t i = 1; i < N; ++i)
accum += arr[i];
return accum;
}
If you want a function template where the type is a template parameter, but the size is a runtime property (which could make sense if you want to avoid binary bloat), then you want something like this:
template <typename T>
void showArrays(T* p, int n) {
for (int i = 0; i < n; ++i) {
std::cout << p[i] << '\n';
}
}
int main() {
std::array<int, 6> myArray = { 1,2,3,4,5,6 };
std::cout << "The array is \n";
showArrays(myArray.data(), 6); // or use myArray.size()
}
You can reuse your template for other kinds of contiguous arrays, too:
float a[] = { 1.1, 2.2, 3.3, 4.4 };
showArrays(a, 4); // full array
showArrays(a + 1, 2); // just the middle two
std::vector<long> v = /* ... */;
showArrays(v.data(), v.size());
std::string s = "hello world";
showArrays(s.data() + 6, 5);
Note that T is a template parameter and not a function parameter. Note further that we never specify an argument for the parameter: that's because the argument is deduced. If you did want to pass a void pointer, like you did in your example, then you would not be able to deduce the template argument from the function call, and you'd have to specify it explicitly:
template <typename T>
void showArrays(void* p, int n) {
// ^^^^^
for (int i = 0; i < n; ++i) {
std::cout << static_cast<T*>(p)[i] << '\n';
// ^^^^^^^^^^^^^^^^^^
// cast to object pointer,
// note that "T" shows up in your code now!
}
}
showArrays<int>(myArray.data(), myArray.size());
// ^^^^^
// explicit template argument

Can I store a typename?

Here is my example class for accessing memory:
class memory {
public:
memory();
template <typename T>
T get(int index);
template <typename T>
void set(int index, T value);
};
And here I use it:
int main(){
memory mem;
float f = mem.get<float>(0);
char* str = mem.get<char*>(1);
mem.set<float>(0, 25); // int passed, upgraded to float
return 0;
}
And I'd like to use it this way:
int main(){
memory<float, char*> mem; // typenames defined only once. Must accept a variable number of template arguments
float f = mem.get(0);
char* str = mem.get(1);
mem.set(0, 25); // int passed, upgraded to float
return 0;
}
How can I implement this? Is it even possible?
You seem to want std::tuple or hana::tuple. It's entirely possible to change you class so that you don't need to send the type each time.
However, you will still need to pass something as a template parameter. Usually, the index of the variable or the index of the type is enough.
The tuple class from the standard library does it like this:
std::tuple<int, std::string> tup;
std::get<0>(tup) = 5; // assign the int
std::get<1>(tup) = "test"; // assign the string
Boost hana skies it in a similar way, but uses operator[]:
hana::tuple<int, std::string> tup;
tup[0_c] = 5; // assign the int
tup[1_c] = "test"; // assign the string
The _c is a user provided literal that transform the int into an integral constant, so the value can be used at compile time.
So how you'd do it?
Simply change your int parameter to a template parameter:
int main() {
memory<float, char*> mem;
float f = mem.get<0>();
char* str = mem.get<1>();
mem.set<0>(25); // int passed, upgraded to float
return 0;
}
And then, to infer what the type is according to the index, use something like this:
template<std::size_t, typename>
struct memory_element; // no basic case
// In this case, we pass a number and a memory class
// We extend the case were the index is decremented, and we remove the first type.
template<std::size_t index, typename Head, typename... Tail>
struct memory_element<index, memory<Head, Tail...> : memory_element<index - 1, memory<Tail...>> {};
// Case where we get to 0
template<typename T, typename... Rest>
struct memory_element<0, memory<T, Rest...>> {
using type = T;
};
// Alias for ease of use
template<std::size_t I, typename M>
using memory_element_t = typename memory_element<I, M>::type;
You can the use it like this:
int main () {
// T1 is int
using T1 = memory_element_t<0, memory<int, float>>;
// T2 is float
using T2 = memory_element_t<1, memory<int, float>>;
}

Recursive templates - constant n size array -> n-1 size in-place?

This may be a bizarre question, but I have a recursive template that expects an array of size d (where d is a template parameter), and I want to pass the d-1 template the same array as if it was one element shorter. This way I only work with one array, instead of creating a new one for each level.
I feel like the answer may be something very basic, but I can't come up with any search terms that result in anything close to what I'm looking for.
To put this into context, here's an example
template<int d>
void Function(int array[d])
{
array[d- 1]= d;
Function<d- 1>(?);
}
This answer is for static, C-style arrays, If your question is about std::Array, I apologize.
Off the top of my head, I came up with two ways to do the recursion, but many more techniques exist.
The first one uses a partially specialized class (with array count of zero) to terminate the recursion.
The second way uses a cast to a statically-chosen type which ends the recursion with an overloaded function. Here, I cast the array to void*, but for types that won't work with this, you could create a custom type which is constructible from the original type.
I resorted to using reinterpret_cast to change the array's type from a reference to array[count] to array[count-1]. Although I expect this to be safe as it is used here, keep in mind that you might run into problems in different situations.
#include <iostream>
// Ends recursion with a partial specialization
template <typename T, int count>
struct StaticArrayDump {
static void func(T(&a)[count]) {
using shorter_t = T(&)[count-1];
StaticArrayDump<T, count-1>::func(reinterpret_cast<shorter_t>(a));
std::cout << a[count-1] << ' ';
}
};
template <typename T>
struct StaticArrayDump<T,0> {
static void func(...) {}
};
template <typename T, int count>
static void static_array_dump_spec(T(&a)[count]) {
using shorter_t = T(&)[count-1];
StaticArrayDump<T,count>::func(a);
}
// Ends recursion with void* cast and function overload
// Ultimately relies on type_select's specialization, however
template <bool, typename A, typename B> struct type_select /* true */ { using type = A; };
template <typename A, typename B> struct type_select<false,A,B> { using type = B; };
template <bool cond, typename A, typename B>
using type_select_t = typename type_select<cond, A, B>::type;
static void static_array_dump_ovld(...) {}
template <typename T, int count>
static void static_array_dump_ovld(T(&a)[count]) {
static const int next_count = count-1;
using shorter_t = T(&)[next_count];
static_array_dump_ovld(reinterpret_cast<
type_select_t<next_count!=0, shorter_t, void*>
>(a));
// output the last element
std::cout << a[count-1] << ' ';
}
// This is an overload-based version which is free of
// any reliance on template specialization.
// helper_trueol's (void*, void*) overload will only be
// selected for arguments (array_ref, count) when count
// is 0, because 0 is the only integer which can be
// converted to a pointer.
// This one's compiler compatibility is a bit shaky...
// MSVC 2013 OK
// IdeOne g++ needs int cast for next_count
static void helper_trueol(void*, void*) {}
template <typename T, int count>
static void helper_trueol(T(&a)[count], int) {
static const int next_count = count-1;
using shorter_t = T(&)[next_count];
helper_trueol(reinterpret_cast<shorter_t>(a), int(next_count));
std::cout << a[count-1] << ' ';
}
template <typename T, int count>
static void static_array_dump_trueol(T(&a)[count]) {
helper_trueol(a, count);
}
// Finally, this overload-based version relies
// on SFINAE to disqualify the template function
// as a candidate when count is 0 because the
// zero-length array type triggeres a substitution
// failure.
// So just using this template array argument type,
// the same one used in all of the previous examples,
// but without any extra mechanisms, is all you need
// to end this recursion!
// This is the obvious best way, of course.
static void static_array_dump_sfinae(...) {}
template <typename T, int count>
static void static_array_dump_sfinae(T(&a)[count]) {
static const int next_count = count-1;
using shorter_t = T(&)[next_count];
static_array_dump_sfinae(reinterpret_cast<shorter_t>(a));
std::cout << a[count-1] << ' ';
}
//////
int main() {
double dbl_array[] = { 0, 1.2, 3.4, 5.6789, 10 };
static_array_dump_spec(dbl_array);
std::cout << '\n';
const char* cstr_array[] = { "zero", "one", "two", "three", "four" };
static_array_dump_ovld(cstr_array);
std::cout << '\n';
char charray[] = "Hello";
charray[sizeof(charray)-1] = '!'; // replace nul terminator
static_array_dump_trueol(charray);
std::cout << '\n';
bool barray[] = {true, true, true, false, true, false, false, false};
std::cout << std::boolalpha;
static_array_dump_sfinae(barray);
std::cout << '\n';
}
Hopefully I am interpreting this correctly but, when you pass the array as a template, I assume you pass an argument for the size of the array. (otherwise how would you know how large the array is?) When you pass the array, you are passing a pointer to the first element of the array, so when you pass the sub array you could just pass a pointer to the next element and size d-1 or an iterator that points to the next element and size d-1.
Example:
template< typename T>
T foo(T * ptr, int size) {
if (size > 0)
return *ptr + foo(ptr + sizeof(T), size - 1);
else
return 0;
}
From the information that you provided i assume you want too know how too "stop" the recursion. This would look something like this:
// this is the function that will be called from the user, it would be bad design too have to pass an integral constant manually when we can easily do this
template <std::size_t I>
inline
void Function(int (&_array)[I])
{
Function(_array, std::integral_constant<std::size_t, I>);
}
// function will recursively do something with an array for each of it's elements
template<std::size_t I>
void Function(int (&_array)[I], std::integral_constant<std::size_t, I>)
{
// do something...
Function(_array,std::integral_constant<std::size_t,I-1>);
}
// function as before with a few modifications
template<std::size_t I>
void Function(int (&_array)[I], std::integral_constant<std::size_t, 1>)
{
// do something...
// exit function...
}

Selection Sort using Templates, invalid conversion string to int, C++

I am trying to do selection sort using a template, I originally coded it for vectors of type int then abstracted it with templates. When I try to use a vector of strings I get the error "No viable conversion from string to int".
I noticed that in my swap function I am using a temp variable of type int, how do you declare a temporary holding variable if you don't know what the value type of the variables will be?
I think the error is in the function swapval.
Also, how do I overload the operator to deal with multiple types? Do templates work for operator overloading?
Here is my code.
template<typename T>
void selection_sort(vector<T>& v)
{
int next = 0;
for (next = 0; next < v.size() -1; next++)
{
int minpos = check_value(v, next, v.size() -1.0);
if (minpos != next) {
swapval( v[minpos], v[next]);
}
}
}
template<typename A, typename B>
void swapval(A& a, B& b)
{
int temp = b; // temp value of int declared here, think this causes error
b = a;
a = temp;
}
template<typename T, typename A, typename B>
int check_value(vector<T>& v, A from, B to)
{
int minpos = from;
for (int i = from; i <= to; i++)
{
if (v[minpos] > v[i])
{
minpos = i;
}
}
return minpos;
}
You should use a single type when swapping:
template<typename T>
void swapval(T& a, T& b)
{
T temp = std::move(b);
b = std::move(a);
a = std::move(temp);
}