Can I store a typename? - c++

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>>;
}

Related

Class template with array or vector arguments

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, ...

How do I get access to template parameters of a template pack parameter

I am trying to create a template class that will enable a compare function to return an integer [ 0 - equal, >0 a should come first, <0 b should come first ].
I am using Sort structs template parameters to keep track of the type that should be used, offset of the field in the string, as well as the order that this field should be kept... so compare can according return the correct value.
Assume for now that the std::string is used to represent a serialized value.
I am having trouble with extracting the information from the template. I have kept sort as a pack parameter, which would be of the type Sort. How do I access these parameters in the code? If there is a better way to refactor this. I looked at some of the other questions related to templates, but didn't see any that would solve this problem. I am using gcc 8.2 and c++17.
#include <cstdint>
#include <string>
#include <cstring>
#include <cassert>
template<typename T, uint32_t offset, char Order = 'A'>
struct Sort {};
template<uint32_t keyLength, template<typename T,uint32_t offset, char Order> class ... sort>
class Comparator {
public:
int compare(std::string & a, std::string &b) {
assert(a.length()==b.length());
// How would I sum the sizeof each T. i.e. if T is int and another T is short, then sum should be 6+keyLength?
assert(a.length()==(sizeof(T)+keyLength)); // Check that my length is equal to key length + all type lengths put together
auto r = memcmp(a.data(),b.data(),keyLength);
if(r!=0) return r;
// How do I retrieve T,offset,Order of each pack parameter.
return internal_compare<T,offset,Order>(a.data(),b.data())? internal_compare<T,offset,Order>(a.data(),b.data()) : ...;
}
private:
template<typename IT,uint32_t iOffset, char iOrder>
int internal_compare(char * a,char *b) {
if constexpr (iOrder=='A'||iOrder=='a') {
return (*(static_cast<IT *>(a+iOffset)))-(*(static_cast<IT *>(b+iOffset)));
} else {
return (*(static_cast<IT *>(b+iOffset)))-(*(static_cast<IT *>(a+iOffset)));
}
}
};
Two things I have not been able to accomplish.
One is getting the sum of sizeof(T) from the sort.
Call the internal compare operator on each sort.
Link to code on compiler explorer
This becomes substantially easier if instead of using this form:
template<typename T, uint32_t offset, char Order = 'A'>
struct Sort {};
template<uint32_t keyLength, template<typename T,uint32_t offset, char Order> class ... sort>
class Comparator;
You use this one:
template <uint32_t keyLength, class...>
class Comparator;
template <uint32_t keyLength, typename... T, uint32_t... offset, char... Order>
class Comparator<keyLength, Sort<T, offset, Order>...> {
// ...
};
First, the original didn't do what you wanted to do anyway. You wanted specific instantiations of Sort but you were actually accepting class templates... like Comparator<32, Sort, Sort, Sort>. Which presumably isn't meaningful.
But when we do it this way, we're not only accepting only instantiations of Sort but we have the parameters in the most useful form. So something like this:
// How would I sum the sizeof each T. i.e. if T is int and another T is short,
// then sum should be 6+keyLength?
Is a fold-expression:
(sizeof(T) + ... + keyLength)
And so forth.
I'll take this problem on another front: how do you extract the template parameters if T has template parameters? Here's an example:
template<typename T>
void foo(T v) {
// T is std::vector<int>, how to extract `int`?
}
int main() {
foo(std::vector{1, 2, 3, 4});
}
There's many answers to that: extraction using partial specialization, type aliases and others.
Here's how you can do it for std::vector:
template<typename>
struct extract_value_type_t {};
template<typename T>
struct extract_value_type_t<std::vector<T>> {
using type = T;
};
template<typename T>
using extract_value_type_t = typename extract_value_type<T>::type;
template<typename T>
void foo(T v) {
// with template specialization
using value_type = extract_value_type_t<T>;
// with the member alias std::vector exposes
// needs much less boilerplate!
using value_type = typename T::value_type;
}
What does doing it with T when it's a vector gives us? Well, if you can do something with a simple type T, you won't even need a template template parameter, making your interface more flexible:
template<typename>
struct sort_traits {};
template<typename T, uint32_t offset_, char order_>
struct sort_traits<Sort<T, offset_, order_>> {
using type = T
static constexpr auto offset = offset_;
static constexpr auto order = order_;
};
Then in your Comparator class, simply do something like that:
template<uint32_t keyLength, typename... sorts>
struct Comparator {
int compare(std::string const& a, std::string const& b) {
return (internal_compare<sorts>(a.data(), b.data()) && ...);
}
private:
template<typename sort>
int internal_compare(char const* a, char const* b) {
using traits = sort_traits<sort>;
using type = typename traits::type;
constexpr auto offset = traits::offset;
constexpr auto order = traits::order;
// do stuff
}
};
This also add the possibility one day to add another kind of sort that would have different template parameters or different things exposed.

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...
}

c++ Default paramaters: is it possible to override a default parameter without overriding earlier default parameters

I have a function:
int function(int a, int b = 1, int c = 2){
return a+b+c;
}
I want to set the value of the "c" variable to 3, but don't want to set the value of "b"
In a language like python I can do this:
function(23,c=3)
However in c++ I cant find a way to do something like that. All examples I could find involved setting the value of "b" before the value of "c", like this:
function(23,1,3);
How can I set the value of a default parameter directly?
This is not possible in C++ (at least not directly). You have the provide all parameters up to the last one you want to provide, and in the order given by the declaration.
You can not do that in C++.
As a workaround you could wrap all parameters as fields with default value in a class (or a struct). You can then have multiple constructors for that class that allow you to set only those fields you are really interested in changing with respect to default.
It is possible in c++... if you're willing to jump through some hoops.
For fun, here is an example of how it might be done:
#include <iostream>
#include <tuple>
#include <type_traits>
#include <utility>
//
// utility to check whether a type is in a list of types
//
template<class T, class...Ts> struct is_in;
template<class T, class U>
struct is_in<T, U>
: std::is_same<T, U>::type {};
template<class T, class U, class...Rest>
struct is_in<T, U, Rest...>
: std::integral_constant<bool, std::is_same<T, U>::value || is_in<T, Rest...>::value>
{};
//
// a wrapper around fundamental types so we can 'name' types
//
template<class Type, class Tag>
struct fundamental {
using value_type = Type;
using tag_type = Tag;
fundamental(Type x) : _x(x) {}
operator const Type&() const { return _x; }
operator Type&() { return _x; }
Type _x;
};
//
// a utility to figure out a fundamental type's value or to take it's default value if it's not present
//
template<class Fundamental, class Tuple, typename = void>
struct value_of_impl
{
static typename Fundamental::value_type apply(const Tuple& t)
{
return Fundamental::tag_type::dflt;
}
};
template<class Fundamental, class...Types>
struct value_of_impl<Fundamental, std::tuple<Types...>, std::enable_if_t<is_in<Fundamental, Types...>::value>>
{
static typename Fundamental::value_type apply(const std::tuple<Types...>& t)
{
return typename Fundamental::value_type(std::get<Fundamental>(t));
}
};
template<class Fundamental, class Tuple>
decltype(auto) value_of(const Tuple& t)
{
return value_of_impl<Fundamental, Tuple>::apply(t);
}
//
// some tag names to differentiate parameter 'name' types
//
struct a_tag { static constexpr int dflt = 0; };
struct b_tag { static constexpr int dflt = 1; };
struct c_tag { static constexpr int dflt = 2; };
//
// define some parameter 'names'
//
using a = fundamental<int, a_tag>;
using b = fundamental<int, b_tag>;
using c = fundamental<int, c_tag>;
//
// the canonical implementation of the function
//
void func(int a, int b, int c)
{
std::cout << a << ", " << b << ", " << c << std::endl;
}
//
// a version that forwards the values of fundamental types in a tuple, or their default values if not present
//
template<class...Fundamentals>
void func(std::tuple<Fundamentals...> t)
{
func(value_of<a>(t),
value_of<b>(t),
value_of<c>(t));
}
//
// a version that converts a variadic argument list of fundamentals into a tuple (that we can search)
//
template<class...Fundamentals>
void func(Fundamentals&&...fs)
{
return func(std::make_tuple(fs...));
}
//
// a test
//
using namespace std;
auto main() -> int
{
func();
func(a(5));
func(c(10), a(5));
func(b(20), c(10), a(5));
return 0;
}
expected output:
0, 1, 2
5, 1, 2
5, 1, 10
5, 20, 10
You can't do that directly, but you can use Named Parameter Idiom (although criticized).
The idea is to create an object encapsulating all parameters, initialize it using method chaining and finally call the function, so the code would look like:
int v = function(params(23).c(3));
Something like this could be done with the named parameter idiom. Here's how it might look in use to have optional parameters (sans the default parameter values):
/*
int function(int a, int b = 1, int c = 2){
return a+b+c;
}
*/
int function( Parameters &p ) {
/* ... */
}
void someOtherFunction() {
function( Parameters().parmW(/*...*/)
/* parmX was omitted here */
.parmY(/*...*/)
.parmZ(/*...*/)
);
Adding default parameters could be done in a few ways. function could be replaced with a class whose purpose is to perform those actions. Parameters could also be written to know which flags were set, then function passes in default values before it begins executing. I'm sure there's plenty of ways to do this, perhaps some a lot better than what I've suggested.

C++ static const array initialization in template class

I have the following template class:
template <unsigned N>
class XArray {
static const int Xdata[N];
};
I want to initialize the static const array for each XArray<N> I used, for example, let XArray<N>::Xdata = {1, 2, 3, ..., N}. How to make it?
you declared a static const int array in your class,so you must define the static member out of the class declaration,just like this:
template<unsigned N>
class XArray
{
public:
static const int array[N];
};
template<unsigned N>
const int XArray<N>::array[N] = {1,2,3,4,5};
But something you must pay attention to is that: when you use this template you must make sure that the "N" bigger than the number of your initialized array;
EDIT:
It seems someone have already provided the solution for your problem in other question, and the answer is quite the same as mine.
Also, for more generic answer, you can check out answers to this question.
Code
If you don't mind using C++11 features, then variadic templates may come handy:
template <unsigned ...Args>
struct XArrayData
{
static const int Values[sizeof...(Args)];
};
template<unsigned N, unsigned ...Args>
struct _XArrayGenerator
{
typedef typename _XArrayGenerator<N - 1, N, Args...>::Xdata Xdata;
};
template<unsigned ...Args>
struct _XArrayGenerator<1, Args...>
{
typedef typename XArrayData<1, Args...> Xdata;
};
template<unsigned N>
struct XArray
{
typedef typename _XArrayGenerator<N>::Xdata Xdata;
};
template <unsigned ...Args>
const int XArrayData<Args...>::Values[sizeof...(Args)] = { Args... };
Explanation
XArray template struct takes the number of array elements as a template parameter (N). In the compilation time, it uses _XArrayGenerator to generate template paremeter list with N consecutive numbers. It begins with the number N, and then recursively uses itself until it reaches 1. At this point, the template parameter list looks like this:
1, 2, ..., N
The last thing to do is to pass these parameters to XArrayData. The last line of the code (definition of the actual array) uses the parameters to initialize the array.
Usage
for (int i = 0; i < 3; ++i)
cout << XArray<3>::Xdata::Values[i] << endl;
Output:
1
2
3
You can initialize as shown below. See inline comments for my explanation.
template <unsigned N>
class XArray {
private:
static const int Xdata[N];
public:
//I added this for illustration purpose
void print()
{
for (int i = 0; i < N; ++i)
{
std::cout << Xdata[i] << std::endl;
}
}
};
//you can initialize like this
//automatic size counting works with static arrays
//here I initialize with 3 elements
//make sure you don't use N < 3 anywhere
template <unsigned N>
const int XArray<N>::Xdata[] = {1,2,3};
int main(void)
{
XArray<3> obj1; //N = 3: This is okay.
XArray<8> obj2; //N > 3: This is okay. Remaining elements will be 0.
XArray<2> obj3; //N < 3: This is also okay.
obj1.print();
obj2.print();
obj3.print(); //but this will give compilation error
return 0;
}