I have written some code to cast const char* to int by using constexpr and thus I can use a const char* as a template argument. Here is the code:
#include <iostream>
class conststr
{
public:
template<std::size_t N>
constexpr conststr(const char(&STR)[N])
:string(STR), size(N-1)
{}
constexpr conststr(const char* STR, std::size_t N)
:string(STR), size(N)
{}
constexpr char operator[](std::size_t n)
{
return n < size ? string[n] : 0;
}
constexpr std::size_t get_size()
{
return size;
}
constexpr const char* get_string()
{
return string;
}
//This method is related with Fowler–Noll–Vo hash function
constexpr unsigned hash(int n=0, unsigned h=2166136261)
{
return n == size ? h : hash(n+1,(h * 16777619) ^ (string[n]));
}
private:
const char* string;
std::size_t size;
};
// output function that requires a compile-time constant, for testing
template<int N> struct OUT
{
OUT() { std::cout << N << '\n'; }
};
int constexpr operator "" _const(const char* str, size_t sz)
{
return conststr(str,sz).hash();
}
int main()
{
OUT<"A dummy string"_const> out;
OUT<"A very long template parameter as a const char*"_const> out2;
}
In this example code, type of out is OUT<1494474505> and type of out2 is OUT<106227495>. Magic behind this code is conststr::hash() it is a constexpr recursion that uses FNV Hash function. And thus it creates an integral hash for const char* which is hopefully a unique one.
I have some questions about this method:
Is this a safe approach to use? Or can this approach be an evil in a specific use?
Can you write a better hash function that creates different integer for each string without being limited to a number of chars? (in my method, the length is long enough)
Can you write a code that implicitly casts const char* to int constexpr via conststr and thus we will not need aesthetically ugly (and also time consumer) _const user-defined string literal? For example OUT<"String"> will be legal (and cast "String" to integer).
Any help will be appreciated, thanks a lot.
Although your method is very interesting, it is not really a way to pass a string literal as a template argument. In fact, it is a generator of template argument based on string literal, which is not the same: you cannot retrieve string from hashed_string... It kinda defeats the whole interest of string literals in templates.
EDIT : the following was right when the hash used was the weighted sum of the letters, which is not the case after the edit of the OP.
You can also have problems with your hash function, as stated by mitchnull's answer. This may be another big problem with your method, the collisions. For example:
// Both outputs 3721
OUT<"0 silent"_const> out;
OUT<"7 listen"_const> out2;
As far as I know, you cannot pass a string literal in a template argument straightforwardly in the current standard. However, you can "fake" it. Here's what I use in general:
struct string_holder //
{ // All of this can be heavily optimized by
static const char* asString() // the compiler. It is also easy to generate
{ // with a macro.
return "Hello world!"; //
} //
}; //
Then, I pass the "fake string literal" via a type argument:
template<typename str>
struct out
{
out()
{
std::cout << str::asString() << "\n";
}
};
EDIT2: you said in the comments you used this to distinguish between several specializations of a class template. The method you showed is valid for that, but you can also use tags:
// tags
struct myTag {};
struct Long {};
struct Float {};
// class template
template<typename tag>
struct Integer
{
// ...
};
template<> struct Integer<Long> { /* ... */ };
// use
Integer<Long> ...; // those are 2
Integer<Float> ...; // different types
Here is the pattern that I am using for template const string parameters.
class F {
static constexpr const char conststr[]= "some const string";
TemplateObject<conststr> instance;
};
see :
https://stackoverflow.com/a/18031951/782168
Related
I have a template function, within which I need to convert a const char * to my template value.
I know for a fact that this const char * was originally read from a ascii text file. My current code looks like this:
template <typename T>
bool Get(T &value, std::string const &query, T const &default)
{
const char* result = DataHandler.GetValue(query);
if (result != NULL)
{
value = static_cast<T>(result); //Here is the issue
return true;
}
value = default
return false;
}
Using this with an int as example i get the error
error C2440: 'static_cast' : cannot convert from 'const char *' to 'int'
Is there a way I can convert the char* to my type T seamlessly, I could not find an answer for this on SO.
In the worst case I can make a case for the 10 types I expect and give an error if not one of these, but I would rather not do it that way if possible.
Is there a way I can convert the char* to my type T seamlessly,
No.
There is no way to make conversion from string to a type automatically work with all types. Such conversion has to be implemented for each class. Typically, it is done by implementing the stream extraction operator >> for std::istream. The built in types such as int and some standard types such as std::string already have such operator. Then you can do for example:
std::istringstream istream(result);
int i;
istream >> i;
Without knowing exactly what you are asking for, using the answer given by #eerorika, here is a generic way to do the conversion:
#include <sstream>
#include <string>
#include <iostream>
template <typename T>
struct DefaultConverter
{
static T Convert(const char *result)
{
std::istringstream istream(result);
T i;
istream >> i;
return i;
}
};
template <typename T, typename Converter = DefaultConverter<T>>
bool Get(T &value, std::string const &query, T const &defaultVal)
{
const char* result = "100";
value = Converter::Convert(result);
return true;
}
int main()
{
int test = 10;
Get(test, "abc123", test);
std::cout << test;
}
The code referring to the DataHandler function is not important to illustrate what the above does.
Basically, the Get function takes an additional argument, namely a conversion template that has an available Convert function that can be called by Get. Note that the default converter simply uses the code as illustrated in the previous answer given by #eerorika.
This gives you the flexibility of providing your own converter that has a Convert function that can do anything customized.
For example:
struct SomeMPEGObject
{
SomeMPEGObject() {}
SomeMPEGObject(const char *) {}
};
struct MPEGConverter
{
static SomeMPEGObject Convert(const char *result)
{
return SomeMPEGObject(result);
}
};
//...
SomeMPEGObject mpeg;
Get<SomeMPEGObject, MPEGConverter>(mpeg, "12345", mpeg);
This will work without changing any code in the Get function.
When using an array non-template type parameter, it seems that size information is basically impossible to recover without passing it separately. For example, in a template
template<const char CStr[]>
struct ToTemp {
...
}
any references to sizeof(CStr) will return 8 (or 4, depending on your system), because it's actually a const char *. You can declare
template<const char CStr[5]>
struct ToTemp {
...
}
or
template<int N, const char CStr[N]>
struct ToTemp {
...
}
but the first one requires knowing the actual size when you're writing the class (not very useful), and the second one requires passing in the size separately anyway (not useful here -- could be useful for enforcing size constraints). Ideally I would have something like
template<const char CStr[int N]> //Let the compiler infer N based on the type
struct ToTemp {
...
}
or
template<int N = -1, const char CStr[N]> //Declare N but let it be forced to a given value, so that I don't have to pass it in
struct ToTemp {
...
}
... but of course neither of those work. In the end, I want to be able to write
const char foo[] = "abcd";
ToTemp<foo> bar;
and have bar correctly understand that sizeof(foo) is 5, without having to pass in a separate sizeof(foo) template argument.
You can use global string literals as a template parameter to match const char[] and calculate length via constexpr function:
constexpr size_t GetSize(const char str[])
{
for (size_t i = 0; ; ++i)
{
if (str[i] == '\0')
{
return i;
}
}
}
template <const char str[]>
struct X
{
constexpr static auto Size = GetSize(str);
};
constexpr const char string[] = "42";
void foo()
{
X<string> x;
static_assert(X<string>::Size == 2, "");
}
So I have the following available:
struct data_t {
char field1[10];
char field2[20];
char field3[30];
};
const char *getData(const char *key);
const char *field_keys[] = { "key1", "key2", "key3" };
This code is given to my and I cannot modify it in any way. It comes from some old C project.
I need to fill in the struct using the getData function with the different keys, something like the following:
struct data_t my_data;
strncpy(my_data.field1, getData(field_keys[0]), sizeof(my_data.field1));
strncpy(my_data.field1, getData(field_keys[1]), sizeof(my_data.field2));
strncpy(my_data.field1, getData(field_keys[2]), sizeof(my_data.field3));
Of course, this is a simplification, and more things are going on in each assignment. The point is that I would like to represent the mapping between keys and struct member in a constant structure, and use that to transform the last code in a loop. I am looking for something like the following:
struct data_t {
char field1[10];
char field2[20];
char field3[30];
};
typedef char *(data_t:: *my_struct_member);
const std::vector<std::pair<const char *, my_struct_member>> mapping = {
{ "FIRST_KEY" , &my_struct_t::field1},
{ "SECOND_KEY", &my_struct_t::field2},
{ "THIRD_KEY", &my_struct_t::field3},
};
int main()
{
data_t data;
for (auto const& it : mapping) {
strcpy(data.*(it.second), getData(it.first));
// Ideally, I would like to do
// strlcpy(data.*(it.second), getData(it.first), <the right sizeof here>);
}
}
This, however, has two problems:
It does not compile :) But I believe that should be easy to solve.
I am not sure about how to get the sizeof() argument for using strncpy/strlcpy, instead of strcpy. I am using char * as the type of the members, so I am losing the type information about how long each array is. In the other hand, I am not sure how to use the specific char[T] types of each member, because if each struct member pointer has a different type I don't think I will be able to have them in a std::vector<T>.
As explained in my comment, if you can store enough information to process a field in a mapping, then you can write a function that does the same.
Therefore, write a function to do so, using array references to ensure what you do is safe, e.g.:
template <std::size_t N>
void process_field(char (&dest)[N], const char * src)
{
strlcpy(dest, getData(src), N);
// more work with the field...
};
And then simply, instead of your for loop:
process_field(data.field1, "foo");
process_field(data.field2, "bar");
// ...
Note that the amount of lines is the same as with a mapping (one per field), so this is not worse than a mapping solution in terms of repetition.
Now, the advantages:
Easier to understand.
Faster: no memory needed to keep the mapping, more easily optimizable, etc.
Allows you to write different functions for different fields, easily, if needed.
Further, if both of your strings are known at compile-time, you can even do:
template <std::size_t N, std::size_t M>
void process_field(char (&dest)[N], const char (&src)[M])
{
static_assert(N >= M);
std::memcpy(dest, src, M);
// more work with the field...
};
Which will be always safe, e.g.:
process_field(data.field1, "123456789"); // just fits!
process_field(data.field1, "1234567890"); // error
Which has even more pros:
Way faster than any strcpy variant (if the call is done in run-time).
Guaranteed to be safe at compile-time instead of run-time.
A variadic templates based solution:
struct my_struct_t {
char one_field[30];
char another_field[40];
};
template<typename T1, typename T2>
void do_mapping(T1& a, T2& b) {
std::cout << sizeof(b) << std::endl;
strncpy(b, a, sizeof(b));
}
template<typename T1, typename T2, typename... Args>
void do_mapping(T1& a, T2& b, Args&... args) {
do_mapping(a, b);
do_mapping(args...);
}
int main()
{
my_struct_t ms;
do_mapping(
"FIRST_MAPPING", ms.one_field,
"SECOND_MAPPING", ms.another_field
);
return 0;
}
Since data_t is a POD structure, you can use offsetof() for this.
const std::vector<std::pair<const char *, std::size_t>> mapping = {
{ "FIRST_FIELD" , offsetof(data_t, field1},
{ "SECOND_FIELD", offsetof(data_t, field2)}
};
Then the loop would be:
for (auto const& it : mapping) {
strcpy(static_cast<char*>(&data) + it.second, getData(it.first));
}
I don't think there's any way to get the size of the member similarly. You can subtract the offset of the current member from the next member, but this will include padding bytes. You'd also have to special-case the last member, subtracting the offset from the size of the structure itself, since there's no next member.
The mapping can be a function to write the data into the appropriate member
struct mapping_t
{
const char * name;
std::function<void(my_struct_t *, const char *)> write;
};
const std::vector<mapping_t> mapping = {
{ "FIRST_KEY", [](data_t & data, const char * str) { strlcpy(data.field1, str, sizeof(data.field1); } }
{ "SECOND_KEY", [](data_t & data, const char * str) { strlcpy(data.field2, str, sizeof(data.field2); } },
{ "THIRD_KEY", [](data_t & data, const char * str) { strlcpy(data.field3, str, sizeof(data.field3); } },
};
int main()
{
data_t data;
for (auto const& it : mapping) {
it.write(data, getData(it.name));
}
}
To iterate over struct member you need:
offset / pointer to the beginning of that member
size of that member
struct Map {
const char *key;
std::size_t offset;
std::size_t size;
};
std::vector<Map> map = {
{ field_keys[0], offsetof(data_t, field1), sizeof(data_t::field1), },
{ field_keys[1], offsetof(data_t, field2), sizeof(data_t::field2), },
{ field_keys[2], offsetof(data_t, field3), sizeof(data_t::field3), },
};
once we have that we need strlcpy:
std::size_t mystrlcpy(char *to, const char *from, std::size_t max)
{
char * const to0 = to;
if (max == 0)
return 0;
while (--max != 0 && *from) {
*to++ = *from++;
}
*to = '\0';
return to0 - to - 1;
}
After having that, we can just:
data_t data;
for (auto const& it : map) {
mystrlcpy(reinterpret_cast<char*>(&data) + it.offset, getData(it.key), it.size);
}
That reinterpret_cast looks a bit ugly, but it just shift &data pointer to the needed field.
We can also create a smarter container which takes variable pointer on construction, thus is bind with an existing variable and it needs a little bit of writing:
struct Map2 {
static constexpr std::size_t max = sizeof(field_keys)/sizeof(*field_keys);
Map2(data_t* pnt) : mpnt(pnt) {}
char* getDest(std::size_t num) {
std::array<char*, max> arr = {
mpnt->field1,
mpnt->field2,
mpnt->field3,
};
return arr[num];
}
const char* getKey(std::size_t num) {
return field_keys[num];
}
std::size_t getSize(std::size_t num) {
std::array<std::size_t, max> arr = {
sizeof(mpnt->field1),
sizeof(mpnt->field2),
sizeof(mpnt->field3),
};
return arr[num];
}
private:
data_t* mpnt;
};
But probably makes the iterating more readable:
Map2 m(&data);
for (std::size_t i = 0; i < m.max; ++i) {
mystrlcpy(m.getDest(i), getData(m.getKey(i)), m.getSize(i));
}
Live code available at onlinegdb.
well i cant find how do this, basically its a variable union with params, basic idea, (writed as function)
Ex1
union Some (int le)
{
int i[le];
float f[le];
};
Ex2
union Some
{
int le;
int i[le];
float f[le];
};
obs this don't works D:
maybe a way to use an internal variable to set the lenght but don't works too.
Thx.
No, this is not possible: le would need to be known at compile-time.
One solution would be to use a templated union:
template <int N> union Some
{
int i[N];
float f[N];
};
N, of course, is compile-time evaluable.
Another solution is the arguably more succinct
typedef std::vector<std::pair<int, float>> Some;
or a similar solution based on std::array.
Depending on your use case you could try to simulate a union.
struct Some
{
//Order is important
private:
char* pData;
public:
int* const i;
float* const f;
public:
Some(size_t len)
:pData(new char[sizeof(int) < sizeof(float) ? sizeof(float) : sizeof(int)])
,i ((int*)pData)
,f ((float*)pData)
{
}
~Some()
{
delete[] pData;
}
Some(const Some&) = delete;
Some& operator=(const Some&) = delete;
};
Alternative solution using templates, unique_ptr and explicit casts:
//max_size_of<>: a recursive template struct to evaluate the
// maximum value of the sizeof function of all types passed as
// parameter
//The recursion is done by using the "value" of another
// specialization of max_size_of<> with less parameter types
template <typename T, typename...Args>
struct max_size_of
{
static const std::size_t value = std::max(sizeof(T), max_size_of<Args...>::value);
};
//Specialication for max_size_of<> as recursion stop
template <typename T>
struct max_size_of<T>
{
static const std::size_t value = sizeof(T);
};
//dataptr_auto_cast<>: a recursive template struct that
// introduces a virtual function "char* const data_ptr()"
// and an additional explicit cast operator for a pointer
// of the first type. Due to the recursion a cast operator
// for every type passed to the struct is created.
//Attention: types are not allowed to be duplicate
//The recursion is done by inheriting from of another
// specialization of dataptr_auto_cast<> with less parameter types
template <typename T, typename...Args>
struct dataptr_auto_cast : public dataptr_auto_cast<Args...>
{
virtual char* const data_ptr() const = 0; //This is needed by the cast operator
explicit operator T* const() const { return (T*)data_ptr(); } //make it explicit to avoid unwanted side effects (manual cast needed)
};
//Specialization of dataptr_auto_cast<> as recursion stop
template <typename T>
struct dataptr_auto_cast<T>
{
virtual char* const data_ptr() const = 0;
explicit operator T* const() const { return (T*)data_ptr(); }
};
//union_array<>: inherits from dataptr_auto_cast<> with the same
// template parameters. Also has a static const member "blockSize"
// that indicates the size of the largest datatype passed as parameter
// "blockSize" is used to determine the space needed to store "size"
// elements.
template <typename...Args>
struct union_array : public dataptr_auto_cast<Args...>
{
static const size_t blockSize = max_size_of<Args...>::value;
private:
std::unique_ptr<char[]> m_pData; //std::unique_ptr automatically deletes the memory it points to on destruction
size_t m_size; //The size/no. of elements
public:
//Create a new array to store "size" elements
union_array(size_t size)
:m_pData(new char[size*blockSize])
,m_size(size)
{
}
//Copy constructor
union_array(const union_array<Args...>& other)
:m_pData(new char[other.m_size*blockSize])
,m_size(other.m_size)
{
memcpy(m_pData.get(), other.m_pData.get(), other.m_size);
}
//Move constructor
union_array(union_array<Args...>&& other)
:m_pData(std::move(other.m_pData))
,m_size(std::move(other.m_size))
{
}
union_array& operator=(const union_array<Args...>& other)
{
m_pData = new char[other.m_size*blockSize];
m_size = other.m_size;
memcpy(m_pData.get(), other.m_pData.get(), other.m_size);
}
union_array& operator=(union_array<Args...>&& other)
{
m_pData = std::move(other.m_pData);
m_size = std::move(other.m_size);
}
~union_array() = default;
size_t size() const
{
return m_size;
}
//Implementation of dataptr_auto_cast<>::data_ptr
virtual char* const data_ptr() const override
{
return m_pData.get();
}
};
int main()
{
auto a = union_array<int, char, float, double>(5); //Create a new union_array object with enough space to store either 5 int, 5 char, 5 float or 5 double values.
((int*)a)[3] = 3; //Use as int array
auto b = a; //copy
((int*)b)[3] = 1; //Change a value
auto c = std::move(a);// move a to c, a is invalid beyond this point
// std::cout << ((int*)a)[3] << std::endl; //This will crash as a is invalid due to the move
std::cout << ((int*)b)[3] << std::endl; //prints "1"
std::cout << ((int*)c)[3] << std::endl; //prints "3"
}
Explanation
template <typename T, typename...Args>
struct max_size_of
{
static const std::size_t value = std::max(sizeof(T), max_size_of<Args...>::value);
};
template <typename T>
struct max_size_of<T>
{
static const std::size_t value = sizeof(T);
};
max_size_of<> is used to get the largest sizeof() value of all types passed as template paremeters.
Let's have a look at the simple case first.
- max_size_of<char>::value: value will be set to sizeof(char).
- max_size_of<int>::value: value will be set to sizeof(int).
- and so on
If you put in more than one type it will evaluate to the maximum of the sizeof of these types.
For 2 types this would look like this: max_size_of<char, int>::value: value will be set to std::max(sizeof(char), max_size_of<int>::value).
As described above max_size_of<int>::value is the same as sizeof(int), so max_size_of<char, int>::value is the same as std::max(sizeof(char), sizeof(int)) which is the same as sizeof(int).
template <typename T, typename...Args>
struct dataptr_auto_cast : public dataptr_auto_cast<Args...>
{
virtual char* const data_ptr() const = 0;
explicit operator T* const() const { return (T*)data_ptr(); }
};
template <typename T>
struct dataptr_auto_cast<T>
{
virtual char* const data_ptr() const = 0;
explicit operator T* const() const { return (T*)data_ptr(); }
};
dataptr_auto_cast<> is what we use as a simple abstract base class.
It forces us to implement a function char* const data_ptr() const in the final class (which will be union_array).
Let's just assume that the class is not abstract and use the simple version dataptr_auto_cast<T>:
The class implements a operator function that returns a pointer of the type of the passed template parameter.
dataptr_auto_cast<int> has a function explicit operator int* const() const;
The function provides access to data provided by the derived class through the data_ptr()function and casts it to type T* const.
The const is so that the pointer isn't altered accidentially and the explicit keyword is used to avoid unwanted implicit casts.
As you can see there are 2 versions of dataptr_auto_cast<>. One with 1 template paremeter (which we just looked at) and one with multiple template paremeters.
The definition is quite similar with the exception that the multiple parameters one inherits dataptr_auto_cast with one (the first) template parameter less.
So dataptr_auto_cast<int, char> has a function explicit operator int* const() const; and inherits dataptr_auto_cast<char> which has a function explicit operator char* const() const;.
As you can see there is one cast operator function implemented with each type you pass.
There is only one exception and that is passing the same template parameter twice.
This would lead in the same operator function being defined twice within the same class which doesn't work.
For this use case, using this as a base class for the union_array, this shouldn't matter.
Now that these two are clear let's look at the actual code for union_array:
template <typename...Args>
struct union_array : public dataptr_auto_cast<Args...>
{
static const size_t blockSize = max_size_of<Args...>::value;
private:
std::unique_ptr<char[]> m_pData;
size_t m_size;
public:
//Create a new array to store "size" elements
union_array(size_t size)
:m_pData(new char[size*blockSize])
,m_size(size)
{
}
//Copy constructor
union_array(const union_array<Args...>& other)
:m_pData(new char[other.m_size*blockSize])
,m_size(other.m_size)
{
memcpy(m_pData.get(), other.m_pData.get(), other.m_size);
}
//Move constructor
union_array(union_array<Args...>&& other)
:m_pData(std::move(other.m_pData))
,m_size(std::move(other.m_size))
{
}
union_array& operator=(const union_array<Args...>& other)
{
m_pData = new char[other.m_size*blockSize];
m_size = other.m_size;
memcpy(m_pData.get(), other.m_pData.get(), other.m_size);
}
union_array& operator=(union_array<Args...>&& other)
{
m_pData = std::move(other.m_pData);
m_size = std::move(other.m_size);
}
~union_array() = default;
size_t size() const
{
return m_size;
}
virtual char* const data_ptr() const override
{
return m_pData.get();
}
};
As you can see union_array<> inherits from dataptr_auto_cast<> using the same template arguments.
So this gives us a cast operator for every type passed as template paremeter to union_array<>.
Also at the end of union_array<> you can see that the char* const data_ptr() const function is implemented (the abstract function from dataptr_auto_cast<>).
The next interesting thing to see is static const size_t blockSize which is initilialized with the maximum sizeof value of the template paremeters to union_array<>.
To get this value the max_size_of is used as described above.
The class uses std::unique_ptr<char[]> as data storage, as std::unique_ptr automatically will delete the space for us, once the class is destroyed.
Also std::unique_ptr is capable of move semantics, which is used in the move assign operator function and the move constructor.
A "normal" copy assign operator function and a copy constructor are also included and copy the memory accordingly.
The class has a constructor union_array(size_t size) which takes the number of elements the union_array should be able to hold.
Multiplying this value with blockSize gives us the space needed to store exactly size elements of the largest template type.
Last but not least there is an access method to ask for the size() if needed.
C++ requires that the size of a type be known at compile time.
The size of a block of data need not be known, but all types have known sizes.
There are three ways around it.
I'll ignore the union part for now. Imagine if you wanted:
struct some (int how_many) {
int data[how_many];
};
as the union part adds complexity which can be dealt with separately.
First, instead of storing the data as part of the type, you can store pointers/references/etc to the data.
struct some {
std::vector<int> data;
explicit some( size_t how_many ):data(how_many) {};
some( some&& ) = default;
some& operator=( some&& ) = default;
some( some const& ) = default;
some& operator=( some const& ) = default;
some() = default;
~some() = default;
};
here we store the data in a std::vector -- a dynamic array. We default copy/move/construct/destruct operations (explicitly -- because it makes it clearer), and the right thing happens.
Instead of a vector we can use a unique_ptr:
struct some {
std::unique_ptr<int[]> data;
explicit some( size_t how_many ):data(new int[how_many]) {};
some( some&& ) = default;
some& operator=( some&& ) = default;
some() = default;
~some() = default;
};
this blocks copying of the structure, but the structure goes from being size of 3 pointers to being size of 1 in a typical std implementation. We lose the ability to easily resize after the fact, and copy without writing the code ourselves.
The next approach is to template it.
template<std::size_t N>
struct some {
int data[N];
};
this, however, requires that the size of the structure be known at compile-time, and some<2> and some<3> are 'unrelated types' (barring template pattern matching). So it has downsides.
A final approach is C-like. Here we rely on the fact that data can be variable in size, even if types are not.
struct some {
int data[1]; // or `0` in some compilers as an extension
};
some* make_some( std::size_t n ) {
Assert(n >= 1); // unless we did `data[0]` above
char* buff = new some[(n-1)*sizeof(int) + sizeof(some)]; // note: alignment issues on some platforms?
return new(buff) some(); // placement new
};
where we allocate a buffer for some of variable size. Access to the buffer via data[13] is practically legal, and probably actually so as well.
This technique is used in C to create structures of variable size.
For the union part, you'll want to create a buffer of char with the right size std::max(sizeof(float), sizeof(int))*N, and expose functions:
char* data(); // returns a pointer to the start of the buffer
int* i() { return reinterpret_cast<int*>(data()); }
float* f() { return reinterpret_cast<float*>(data()); }
you may also need to properly initialize the data as the proper type; in theory, a char buffer of '\0's may not correspond to defined float values or ints that are zero.
I would like to suggest a different approach: Instead of tying the number of elements to the union, tie it outside:
union Some
{
int i;
float f;
};
Some *get_Some(int le) { return new Some[le]; }
Don't forget to delete[] the return value of get_Some... Or use smart pointers:
std::unique_ptr<Some[]> get_Some(int le)
{ return std::make_unique<Some[]>(le); }
You can even create a Some_Manager:
struct Some_Manager
{
union Some
{
int i;
float f;
};
Some_Manager(int le) :
m_le{le},
m_some{std::make_unique<Some[]>(le)}
{}
// ... getters and setters...
int count() const { return m_le; }
Some &operator[](int le) { return m_some[le]; }
private:
int m_le{};
std::unique_ptr<Some[]> m_some;
};
Take a look at the Live example.
It's not possible to declare a structure with dynamic sizes as you are trying to do, the size must be specified at run time or you will have to use higher-level abstractions to manage a dynamic pool of memory at run time.
Also, in your second example, you include le in the union. If what you were trying to do were possible, it would cause le to overlap with the first value of i and f.
As was mentioned before, you could do this with templating if the size is known at compile time:
#include <cstdlib>
template<size_t Sz>
union U {
int i[Sz];
float f[Sz];
};
int main() {
U<30> u;
u.i[0] = 0;
u.f[1] = 1.0;
}
http://ideone.com/gG9egD
If you want dynamic size, you're beginning to reach the realm where it would be better to use something like std::vector.
#include <vector>
#include <iostream>
union U {
int i;
float f;
};
int main() {
std::vector<U> vec;
vec.resize(32);
vec[0].i = 0;
vec[1].f = 42.0;
// But there is no way to tell whether a given element is
// supposed to be an int or a float:
// vec[1] was populated via the 'f' option of the union:
std::cout << "vec[1].i = " << vec[1].i << '\n';
}
http://ideone.com/gjTCuZ
Can I use C++ template classes to differentiate object types? Or what should I use?
Eg. I have a class Synonym and it can be of type Statement, Procedure, etc for example. I have functions that accepts these synonyms and evaluates them depending on its type. So I was thinking it will be nice if I can do something like:
enum Types { Statement, Procedure, Variable, ... };
template <typename Types>
class Synonym { ... }
void evaluate(Synonym<Statement> s, Synonym<Variable> v) { do something }
^ so that I can do this ... instead of checking the type in function like:
void evaluate(Synonym s, Synonym v) {
assert(s.type == Statement);
assert(v.type == Variable);
// also would like to eliminate things like: (if possible)
switch(s.type) {
case XXX: doSomething ...
case YYY: doAnotherThing ...
}
}
You could create a function template and then specialize on that template
template<typename Type>
void evaluate (Type t) {}
template<>
void evaluate<Statement>( Statement s)
{}
This way, when you pass a Statement it will pick that overload, and you can do different behaviors depending on type.
I think using a variant and visitor pattern would be suited. Have a look at Boost.Variant here: http://www.boost.org/doc/libs/1_51_0/doc/html/variant.html, the last example (also below but expanded) shows a visitor implementation. There are also other variant and visitor implementations. std::any and loki are also options. I personally like loki but that is probably just because I'm a huge fan of Alexandrescu.
#include "boost/variant.hpp"
#include <iostream>
class ToLengthVisitor : public boost::static_visitor<int>
{
public:
int operator()(int i) const
{
return i;
}
int operator()(const std::string & str) const
{
return str.length();
}
int operator()(const char * str) const
{
const char * temp = str;
while(*temp != '\0') temp++;
return temp-str;
}
};
int main()
{
typedef boost::variant< int, std::string, const char * > MyVariant;
MyVariant u(std::string("hello world"));
std::cout << u; // output: hello world
MyVariant cu(boost::get<std::string>(u).c_str());
int result = boost::apply_visitor( ToLengthVisitor(), u );
std::cout << result; // output: 11 (i.e., length of "hello world")
result = boost::apply_visitor( ToLengthVisitor(), cu );
std::cout << result; // output: 11 (i.e., length of "hello world")
}