I have many C++ functions in a DLL that I made specifically for Excel to call.
I frequently pass to these functions as parameters OLE VARIANTs that contain SafeArrays.
I wrote a function to act as a guard to ensure that a passed VARIANT actually contains a SafeArray and that the array is of the proper type for the occasion, both in terms of datatype and number of dimensions.
If those three criteria are satisfied the function returns a pointer to the first element and also has two out parameters to return the number of elements in each dimension (note: I only care about 1d and 2d SafeArrays).
Here is the function:
PVOID SafeArrayDataPointer(VARIANT &v, const long &ArrayType, const long &ArrayDims, long &Elems1D, long &Elems2D) {
SAFEARRAY* pSafeArray = NULL;
if ( V_VT(&v) & VT_ARRAY ) {
if ( ArrayType != (V_VT(&v) & VT_TYPEMASK) ) return NULL;
pSafeArray = V_ARRAY(&v);
if ( ArrayDims != pSafeArray->cDims ) return NULL;
switch (ArrayDims) {
case 2:
Elems1D = (pSafeArray->rgsabound)[1].cElements;
Elems2D = (pSafeArray->rgsabound)[0].cElements;
break;
case 1:
Elems1D = (pSafeArray->rgsabound)[0].cElements;
Elems2D = 0;
break;
default:
Elems1D = 0;
Elems2D = 0;
break;
}
return pSafeArray->pvData;
} else return NULL;
}
This function works well and allows me to conveniently grab the data pointer and to get the number of elements in each dimension by calling like this (assuming vData is a VARIANT passed from Excel:
pDataArray = (VARIANT*) SafeArrayDataPointer(vData, VT_VARIANT, 2, Elems1D, Elems2D); if (pDataArray == NULL) goto error1;
However, there are two things that I do not like about this:
1.) Since the function returns a PVOID I have to cast to the relevant pointer type... but this is redundant as I've already specfied in the second argument what type of array must be contained in the VARIANT. For example in a different situation I may need to make sure that the array is of long values:
pDataArray = (long*) SafeArrayDataPointer(vData, VT_I4, 1, Elems1D, Junk); if (pDataArray == NULL) goto error1;
Again, this works fine, but it is redundant. I would much prefer some mechanism that allows the function to return the correct type of pointer. And I'm hoping this can be done without templates.
2.) I can't figure out how to NOT have the Junk parameter in the second example where I specify that the array must be 1d. Obviously, in such a case, there are no elements in the second dimension.
If you don't want to use templates, and you don't want specialized functions, you could use a gross macro to solve the first problem about having to cast from PVOID every time you call SafeArrayVariantPointer:
Something like this:
#define CAST_TYPE_VT_VARIANT (VARIANT *)
#define CAST_TYPE_VT_LONG (long *)
#define SAFE_ARRAY_DATA_POINTER(vData, vType, dimSize, elems1D, elems2D) \
CAST_TYPE_##vType SafeArrayDataPointer((vData), (vType), (dimSize), (elems1D), (elems2D))
Then you can call like:
VARIANT *pDataArray = SAFE_ARRAY_DATA_POINTER(vData, VT_VARIANT, 2, Elems1D, Elems2D);
But first you need to change your method signature so the ArrayType argument is taken as a long not a const long &.
Note this assumes the second parameter to SAFE_ARRAY_DATA_POINTER macro must be a literal that corresponds to one of your defined CAST_TYPE_* macros. It can't be a variable.
For you second question about the redundant Junk parameter, you can create an overloaded SafeArrayDataPointer function which only returns the size of first dimension. It can call the first version of SafeArrayDataPointer and discard the size of the second dimension.
Something like:
PVOID SafeArrayDataPointer(VARIANT &v, long ArrayType, const long &ArrayDims, long &Elems1D)
{
long Elems2D;
PVOID *toReturn = SafeArrayDataPointer(v, ArrayType, ArrayDims, Elems1D, Elems2D);
if (Elems2D != 0) toReturn = NULL;
return toReturn;
}
However, to solve this problem, I would probably use templates.
First, create a set of array_type_traits classes which expose a typedef for your cast type given a long representing VT_LONG, VT_VARIANT, etc.
//Generic array_type_traits class
template<long array_type>
class array_type_traits
{
public:
typedef PVOID cast_type;
};
//Specialized for VT_LONG
template<>
class array_type_traits<VT_LONG>
{
public:
typedef long * cast_type;
};
//Specialized for VT_VARIANT
template<>
class array_type_traits<VT_VARIANT>
{
public:
typedef VARIANT * cast_type;
};
Continue to specialize these for each VT_* type you have.
Next, encapsulate your SafeArrayDataPointer function inside a class SafeArrayDataPointerBase.
//Base class which has one static function Get() that returns a PVOID
class SafeArrayDataPointerBase
{
protected:
static PVOID Get(VARIANT& vData, long vType, long dimSize, long& elems1D, long& elems2D)
{
// Place your SafeArrayDataPointer function code here
}
};
Now create your class which will call `SafeArrayDataPointerBase::Get() and then cast the result to the correct type.
template<long ArrayType>
class SafeArrayDataPointer : public SafeArrayDataPointerBase
{
public:
typedef typename array_type_traits<ArrayType>::cast_type cast_type;
static cast_type Get(VARIANT& v, long ArrayDims, long& Elems1D, long& Elems2D)
{
return (cast_type) SafeArrayDataPointerBase::Get(v, ArrayDims, ArrayType, Elems1D, Elems2D);
}
};
And finally, you would call the template class as so:
VARIANT *vp = SafeArrayDataPointer<VT_VARIANT>::Get(v, ArrayDims, Elems1D, Elems2D);
long *vl = SafeArrayDataPointer<VT_LONG>::Get(v, ArrayDims, Elems1D, Elems2D);
Smth like this:
template<int vt> struct vt_type_disp;
template<> struct vt_type_disp<VT_I4> { typedef LONG type; };
template<> struct vt_type_disp<VT_VARIANT> { typedef VARIANT type; };
template<int vt> using vt_type = typename vt_type_disp<vt>::type;
template<int vtElem>
auto unpack_array(VARIANT& v, ULONG& d1_size)
{
if ((V_VT(&v) & VT_ARRAY) && (V_VT(&v) & VT_TYPEMASK) == vtElem)
{
SAFEARRAY* p = (V_VT(&v) & VT_BYREF) ? *V_ARRAYREF(&v) : V_ARRAY(&v);
if (p->cDims == 1)
{
d1_size = p->rgsabound[0].cElements;
return static_cast<vt_type<vtElem>*>(p->pvData);
}
}
return static_cast<vt_type<vtElem>*>(nullptr);
}
template<int vtElem>
auto unpack_array(VARIANT& v, ULONG& d1_size, ULONG& d2_size)
{
if ((V_VT(&v) & VT_ARRAY) && (V_VT(&v) & VT_TYPEMASK) == vtElem)
{
SAFEARRAY* p = (V_VT(&v) & VT_BYREF) ? *V_ARRAYREF(&v) : V_ARRAY(&v);
if (p->cDims == 2)
{
d1_size = p->rgsabound[1].cElements;
d2_size = p->rgsabound[0].cElements;
return static_cast<vt_type<vtElem>*>(p->pvData);
}
}
return static_cast<vt_type<vtElem>*>(nullptr);
}
// functions to export from dll (if you need them)
auto unpack_array_I4_1D(VARIANT &v, ULONG& dim_size) { return unpack_array<VT_I4>(v, dim_size); }
auto unpack_array_I4_2D(VARIANT &v, ULONG& d1_size, ULONG& d2_size) { return unpack_array<VT_I4>(v, d1_size, d2_size); }
auto unpack_array_VARIANT_1D(VARIANT &v, ULONG& dim_size) { return unpack_array<VT_VARIANT>(v, dim_size); }
auto unpack_array_VARIANT_2D(VARIANT &v, ULONG& d1_size, ULONG& d2_size) { return unpack_array<VT_VARIANT>(v, d1_size, d2_size); }
// etc
Note: your code doesn't handle VT_BYREF properly
Related
I am trying to reduce code duplication through templates. I already moved most code to this helper iterate_function_from_CSC_helper which is now a template. However, this function still repeats a lot of code just to call a different specialization of a template:
std::function<std::pair<int, double>(int idx)>
IterateFunctionFromCSC(const void* col_ptr, int col_ptr_type, const int32_t* indices, const void* data, int data_type, int64_t ncol_ptr, int64_t , int col_idx) {
CHECK(col_idx < ncol_ptr && col_idx >= 0);
if (data_type == C_API_DTYPE_FLOAT32) {
if (col_ptr_type == C_API_DTYPE_INT32) {
return iterate_function_from_CSC_helper<float, int32_t>(col_ptr, indices, data, col_idx);
} else if (col_ptr_type == C_API_DTYPE_INT64) {
return iterate_function_from_CSC_helper<float, int64_t>(col_ptr, indices, data, col_idx);
}
} else if (data_type == C_API_DTYPE_FLOAT64) {
if (col_ptr_type == C_API_DTYPE_INT32) {
return iterate_function_from_CSC_helper<double, int32_t>(col_ptr, indices, data, col_idx);
} else if (col_ptr_type == C_API_DTYPE_INT64) {
return iterate_function_from_CSC_helper<double, int64_t>(col_ptr, indices, data, col_idx);
}
}
Log::Fatal("Unknown data type in CSC matrix");
return nullptr;
}
I'd like to automatically map the integers data_type and col_ptr_dtype which are received at runtime to the types float/double and int32_t/int64_t respectively and calling the template with those. Something like this:
std::function<std::pair<int, double>(int idx)>
IterateFunctionFromCSC(const void* col_ptr, int col_ptr_type, const int32_t* indices, const void* data, int data_type, int64_t ncol_ptr, int64_t , int col_idx) {
CHECK(col_idx < ncol_ptr && col_idx >= 0);
if (<TTag<data_col>::invalid_type || TTag<col_ptr_type>::invalid_type) {
Log::Fatal("Unknown data type in CSC matrix");
return nullptr;
}
return iterate_function_from_CSC_helper<TTag<data_type>::type, TTag<col_ptr_type>::type>(col_ptr, indices, data, col_idx);
}
Is that possible? I assumed with some metaprogramming one could eliminate this.
I tried the following but cannot make dummy_IterateFunctionFromCSC consume a non const input (which will be the case at runtime):
#include <cstdint>
#include <stdio.h>
#include <iostream>
#include <type_traits>
#define C_API_DTYPE_FLOAT32 (0) /*!< \brief float32 (single precision float). */
#define C_API_DTYPE_FLOAT64 (1) /*!< \brief float64 (double precision float). */
#define C_API_DTYPE_INT32 (2) /*!< \brief int32. */
#define C_API_DTYPE_INT64 (3) /*!< \brief int64. */
struct TTagInvalidType {}; //! Meant for invalid types in TTag.
template <int C_API_DTYPE>
struct TTag {
using type = TTagInvalidType;
};
template<>
struct TTag<C_API_DTYPE_FLOAT32> {
using type = float;
};
template <>
struct TTag<C_API_DTYPE_FLOAT64> {
using type = double;
};
template <>
struct TTag<C_API_DTYPE_INT32> {
using type = int32_t;
};
template <>
struct TTag<C_API_DTYPE_INT64> {
using type = int64_t;
};
template <typename T>
void example_f () {
T x = 3.6;
std::cout << x << "\n";
}
template <>
void example_f<TTagInvalidType>() {
std::cout << "Abort!\n";
}
template<int x>
void dummy_IterateFunctionFromCSC() {
f<typename TTag<x>::type>();
}
int main() {
const int m = 2; // Doesn't work for non const integers (true at runtime)
dummy_IterateFunctionFromCSC<m>();
}
This compiles but only with constant m, not with an integer received from the user for instance.
Is this impossible because the type-dispatching must be computed at compile time? Or is it possible and how? :D
Thank you :)
Turning runtime value to compile time value requires indeed some if/switch like you did.
You might avoid some duplication by additional split:
C++17 might help reduce verbosity with std::variant, some utilities:
template <typename T> struct type_identity { using type = T; };
// type should be an enum
std::variant<type_identity<int32_t>, type_identity<int64_t>> to_compile_int_type(int type)
{
switch (type) {
case C_API_DTYPE_INT32: return type_identity<int32_t>{};
case C_API_DTYPE_INT64: return type_identity<int64_t>{};
default:
Log::Fatal("Unknown int data type");
throw "unknown type";
}
}
// type should be an enum
std::variant<type_identity<float>, type_identity<double>> to_compile_float_type(int type)
{
switch (type) {
case C_API_DTYPE_FLOAT32: return type_identity<float>{};
case C_API_DTYPE_FLOAT64: return type_identity<double>{};
default:
Log::Fatal("Unknown float data type");
throw "unknown type";
}
}
And then
std::function<std::pair<int, double>(int idx)>
IterateFunctionFromCSC(const void* col_ptr,
int col_ptr_type,
const int32_t* indices,
const void* data,
int data_type,
int64_t ncol_ptr,
int64_t ,
int col_idx)
{
CHECK(col_idx < ncol_ptr && col_idx >= 0);
std::visit(
[&](auto intvar, auto floatvar){
using inttype = typename decltype(intvar)::type;
using floattype = typename decltype(floatvar)::type;
return iterate_function_from_CSC_helper<floatype, inttype>(col_ptr, indices, data, col_idx);
},
to_compile_int_type(col_ptr_type),
to_compile_float_type(data_type)
);
}
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.
I am building a custom BDD class to store different types of data (e.g., long, char*, double, …) for my program.
In order to store the data, I need a struct for each table, like this:
struct MYSTRUCT0
{
char variable0[10];
char variable1[70];
};
struct MYSTRUCT1
{
long variable0;
long variable1;
char variable2[6];
double variable3;
};
But it's much work each time I need a new table, because I need to write a function to save each table in a file, to read it, etc. Worse, it's not really object-oriented.
So my question is, is there a way to "browse" the struct to simplify my code?
Something like this:
for(int v=0; v<arraysize; v++)
for(int i=0; i<MYSTRUC0.length; i++)
{
if (MYSTRUCT.getvar(i).type == long)
DoSomethingForLong(myarray(v).getval(i));
if (MYSTRUCT.getvar(i).type == char*)
DoSomethingForCharPtr(myarray(v).getval(i));
}
I know it's possible for code like this to work directly in C++. I just use it to illustrate what I mean.
Below code is just an example of how you can make your own "variable-type-aware" struct that maybe what you want:
#include <vector>
enum MyTypes
{
LONG,
CHARPTR,
DOUBLE,
} myTypes;
struct MyStruct
{
MyStruct(long longVar)
{
variable.longVar = longVar;
whichType = LONG;
}
MyStruct(char* charPtr)
{
variable.charPtr = charPtr;
whichType = CHARPTR;
}
MyStruct(double var)
{
variable.var = var;
whichType = DOUBLE;
}
~MyStruct()
{
}
MyTypes whichType;
union {
long longVar;
char* charPtr;
double var;
} variable;
};
void DoSomethingForLong(MyStruct* doubleStruct)
{
/*Do something specific to long*/
};
void DoSomethingForCharPtr(MyStruct* doubleStruct)
{
/*Do something specific to char pointer*/
};
void DoSomethingForDouble(MyStruct* doubleStruct)
{
/*Do something specific to double*/
};
int main()
{
std::vector<MyStruct*> myVec;
// add a struct with long variable
long longVar = 2000000000;
MyStruct* myLongStruct = new MyStruct(longVar);
myVec.push_back(myLongStruct);
// add a struct with char pointer
char* charArray = new char[1000];
MyStruct* myCharPtrStruct = new MyStruct(charArray);
myVec.push_back(myCharPtrStruct);
// add a struct with double variable
double doubleVar = 200.200;
MyStruct* myDoubleStruct = new MyStruct(doubleVar);
myVec.push_back(myDoubleStruct);
for (int i = 0; i < myVec.size(); ++i)
{
MyStruct* tempStruct = myVec[i];
if (tempStruct->whichType == LONG)
{
DoSomethingForLong(tempStruct);
}
else if (tempStruct->whichType == CHARPTR)
{
DoSomethingForCharPtr(tempStruct);
}
else if (tempStruct->whichType == DOUBLE)
{
DoSomethingForDouble(tempStruct);
}
}
if (myLongStruct)
{
delete myLongStruct;
myLongStruct = nullptr;
}
if (myCharPtrStruct)
{
if (charArray)
{
delete[] charArray;
charArray = nullptr;
}
delete myCharPtrStruct;
myCharPtrStruct = nullptr;
}
if (myDoubleStruct)
{
delete myDoubleStruct;
myDoubleStruct = nullptr;
}
}
If you go to the trouble of adding a member function that can export your data members as a tuple, then we can use some template meta programming to make this work.
Live Demo (C++14)
First, the alteration:
struct MYSTRUCT0
{
char variable0[10];
char variable1[70];
std::tuple<char(&)[10], char(&)[70]> GetData()
{
return std::tie(variable0, variable1);
}
};
struct MYSTRUCT1
{
long variable0;
long variable1;
char variable2[6];
double variable3;
std::tuple<long&, long&, char(&)[6], double&> GetData()
{
return std::tie(variable0, variable1, variable2, variable3);
}
};
std::tie will put references to these members into a tuple.
The nice thing about a tuple is that it encodes all the types into a list that we can take advantage of. (You could probably write macro(s) to create these structs for you.)
From here the strategy is to write a function that can process any tuple.
Since we access elements of a tuple with a call to std::get<i> where i is some index, we need a way to get indices for these elements, so we introduce a level of indirection to create them using a std::index_sequence:
template<class... T>
void ProcessData(const std::tuple<T...>& data){
std::cout << "Processing " << sizeof...(T) << " data elements...\n";
detail::ProcessDataImpl(data, std::make_index_sequence<sizeof...(T)>{});
}
The definition of detail::ProcessDataImpl is going to use a technique called simple pack expansion. It's a trick where we take advantage of array initialization to call a function for each element in a parameter pack. It looks a little weird, but bear with me:
template<class... T, size_t... I>
void ProcessDataImpl(const std::tuple<T...>& data, std::index_sequence<I...>){
using swallow = int[];
(void)swallow{0, (void(ProcessElement(std::get<I>(data))), 0)...};
}
This will call a function called ProcessElement for each element in the tuple. We use the comma operator and void casting to ensure that the function doesn't really do anything, and all our operations are solely for their side effects (calling our ProcessElement function).
Our ProcessElement function will use yet another level of indirection to pass on the argument for processing for more complicated types like our character arrays. Otherwise we can overload it for the types that we need:
template<class T>
struct ProcessElementImpl
{
static void apply(const T& element)
{
static_assert(sizeof(T) == 0, "No specialization created for T");
}
};
template<size_t N>
struct ProcessElementImpl<char[N]>
{
static void apply(const char(&arr)[N])
{
std::cout << "Process char array of size " << N << std::endl;
}
};
template<class T>
void ProcessElement(const T& element)
{
ProcessElementImpl<T>::apply(element);
}
void ProcessElement(long _element)
{
std::cout << "Process a long\n";
}
void ProcessElement(double _element)
{
std::cout << "Process a double\n";
}
Notice that we overloaded for long and double, but we passed it along to ProcessElementImpl for our character array. This is required because we cannot partially specialize a template function, and we want to process arbitrarily-sized arrays.
The base class template also contains a static_assert so that we're forced to write a specialization for exporting a data type.
Finally we can call it like so:
int main()
{
MYSTRUCT0 struct0;
ProcessData(struct0.GetData());
MYSTRUCT1 struct1;
ProcessData(struct1.GetData());
return 0;
}
Output:
Processing 2 data elements...
Process char array of size 10
Process char array of size 70
Processing 4 data elements...
Process a long
Process a long
Process char array of size 6
Process a double
I'm trying to rewrite some code I wrote time ago with a functional language (OCaml) into C++.
My problem can be shortened into:
I have a stack of values
a value can be of a variant type (so a set of different kinds of values, eg int, float, std::string, std::list whatever)
I want to define operators which work on the values (eg an addition operation which pops two values and pushes the sum of them)
some operators behaves differently according to the types which are found on the stack, ideally some operators even change the number of arguments according to the type (a simple example: addition operator could pop one value, if it's a std::list then push the operator applied between all values of the list, otherwise pops another value and do the addition if they're both float)
Up to now I've been able to make it work by using templates eg.
class Value
{
public:
Value(Type type) : type(type) { }
virtual string svalue() const = 0;
virtual string lvalue();
virtual bool equals(Value *value) const = 0;
virtual Value* clone() const = 0;
const Type type;
virtual ~Value() { };
}
template <class T>
class TValue : public Value
{
protected:
T value;
public:
TValue(Type type, T value) : Value(type), value(value) {}
void set(T value) { this->value = value; }
T get() const { return this->value; }
};
class Int : public TValue<int>
{
private:
public:
Int(int value) : TValue<int>(TYPE_INT, value) { };
virtual string svalue() const;
virtual bool equals(Value *value) const { return this->value == ((TValue<int>*)value)->get(); }
virtual Value *clone() const { return new Int(value); }
};
and then operators are interpreted by doing
Value *v1, *v2,
case OP_PLUS:
{
if (vm->popTwo(&v1, &v2))
{
switch (v1->type << 4 | v2->type)
{
case TYPES(TYPE_INT, TYPE_INT): vm->push(new Int(((Int*)v1)->get() + ((Int*)v2)->get())); break;
case TYPES(TYPE_FLOAT, TYPE_INT): vm->push(new Float(((Float*)v1)->get() + ((Int*)v2)->get())); break;
case TYPES(TYPE_INT, TYPE_FLOAT): vm->push(new Float(((Int*)v1)->get() + ((Float*)v2)->get())); break;
case TYPES(TYPE_FLOAT, TYPE_FLOAT): vm->push(new Float(((Float*)v1)->get() + ((Float*)v2)->get())); break;
}
}
break;
}
Now, this works but I don't like the approach because it sounds quite clumsy, it requires a lot of type casts and it is not elegant at all (compared to my functional implementation). I'm starting to looking into boost library to see if I can find a better way to manage everything, before starting with it I was trying to define a different way of defining operators such as
template <Opcode T, class X, class A>
class Unary
{
public:
static A* ptr(X* x)
{
cout << "Missing instruction!" << endl;
return NULL;
};
};
template <>
class Unary<OP_MINUS, Float, Float>
{
public:
static Float *ptr(Float *x) { return new Float(-x->get()); };
};
So that I'm able to do
Float *a = new Float(10);
Float *r = Unary<OP_MINUS, Float, Float>::ptr(f);
This works but I'm still unable to see how I am supposed to manage it in a generic way so that I can call the right function according to what is found on the stack and which operators is used.
Will boost help me somehow? What I would like to have is a solution that is type safe and elegant at the same time but boost has so many different libraries that is hard for me to just understand what to look for. I don't need to use it if there is something easier that I am missing, I didn't think to find so many difficulties when dropping a functional language for this kind of task.
You want boost::variant, and for the list-of-elements, boost::make_recursive_variant (so you can refer to the type inside the type).
While apply_visitor lets you apply a function to many types, I find something like this easier to think about to start (assuming C++11 support in your compiler):
template<typename T, typename Func, typename Types...>
bool TryApplyFuncOn( boost::variant<Types...>& var, Func f ) {
struct HelperVisitor {
HelperVisitor( Func f_ ):func(f_) {}
Func func;
typedef bool return_type;
template<typename U>
return_type operator()( U& unused ) { return false; }
return_type operator()( T& t ) { f(t); return true; }
};
return boost::apply_visitor( HelperVisitor(f), var );
}
which takes a type you want to apply a function on, and a variant, and applies it iff the type you asked to be applied is the type in the variant. It returns true if it found a match.
The general case lets you do this "in one pass".
So you can do something like:
// easy case:
typedef boost::variant<int,double> scalar;
scalar times_two(scalar const& left) {
scalar retval = left;
TryApplyFuncOn<int>( retval, []( int& value ){ value*=2; } );
TryApplyFuncOn<double>( retval, []( double& value ){ value*=2.; } );
return retval;
}
// tricky case:
scalar multiply(scalar const& left, scalar const& right) {
scalar retval = left;
TryApplyFuncOn<int>( retval, [&right]( int& left_value ){
TryApplyFuncOn<int>( right, [&left_value]( int& right_value ){
left_value *= right_value;
});
TryApplyFuncOn<double>( right, [&left_value]( double& right_value ){
left_value *= right_value;
});
});
TryApplyFuncOn<double>( retval, [&right]( double& left_value ){
TryApplyFuncOn<int>( right, [&left_value]( int& right_value ){
left_value *= right_value;
});
TryApplyFuncOn<double>( right, [&left_value]( double& right_value ){
left_value *= right_value;
});
});
return retval;
}
which doesn't yet do type promotion (so int*double doesn't become a double), but there isn't anything fundamental stopping that.
Make sense?
I am rewriting a C wrapper around a C Python API (Python 1.5) and I noticed that the function Py_VaBuildValue uses variadic number of args. I wondered if I have to use the same in my C++ function wrapper to pass to this function or if there is a more C++ way to deal with this?
I know variadic functions can be the cause of untold trouble, so I'd rather avoid having to use if there is a better way.
EDIT:
So here is the C code I need to make into a C++ function:
int Set_Global(char *modname, char *varname, char *valfmt, ... /* cval(s) */) {
int result;
PyObject *module, *val; // "modname.varname = val"
va_list cvals;
va_start(cvals, valfmt); // C args after valfmt
module = Load_Module(modname); // get/load module
if (module == NULL)
return -1;
val = Py_VaBuildValue(valfmt, cvals); // convert input to Python
va_end(cvals);
if (val == NULL)
return -1;
result = PyObject_SetAttrString(module, varname, val);
Py_DECREF(val); // set global module var
return result; // decref val: var owns it
}
So I'm making the same function with std::string instead of char* and I want to change the ellipsis to something more c++ like, that I can however then pass to Py_VaBuildValue inside the function.
If you want to be clever and don't fear some heavy template wizardry, it should be possible to generate (or massage) valfmt to always match the types you want to pass (I am assuming it uses format specifiers similar to printf, but the technique is applicable to any kind of format specification). You could do something like:
template <typename T> struct format_trait;
template <> struct format_trait<int> { static const char * format() { return "%i"; }};
template <> struct format_trait<unsigned> { static const char * format() { return "%u"; }};
... // and so on for each type you want to use
template <typename Arg1>
int Set_Global(const std::string &modname, const std::string &varname, const Arg1 &arg1)
{
return ::Set_Global(modname.c_str(), varname.c_str(), format_trait<Arg1>::format(), arg1);
}
template <typename Arg1, typename Arg2>
int Set_Global(const std::string &modname, const std::string &varname, const Arg1 &arg1, const Arg2 &arg2)
{
return ::Set_Global(modname.c_str(), varname.c_str(),
std::string(format_trait<Arg1>::format()) + format_trait<Arg2>::format(),
arg1, arg2);
}
... // Repeat up to number of argument you reasonably expect to need or use C++0x variadic templates.
This is the simple way where each value is formatted the default way and combined together. If you want something more complex, you can create a function, that will get valfmt string and correct format specifiers (obtained from the trait) and will fix up the format string to match.
You may write template function which will check the correctness of params, and won't allow your program to crash.
bool BuildValueCheck(const char * s, int v)
{
if( s[0] == 'i' )
return true;
return false;
}
bool BuildValueCheck(const char * s, float v)
{
if( s[0] == 'f' )
return true;
return false;
}
bool BuildValueCheck(const char * s, char * v)
{
if( s[0] == 's' || s[0] == 'z' )
return true;
return false;
}
// and so on for each other type
template<typename t1>
PyObject *BuildValue(char * format, t1 v1)
{
char * s = strchr(format, "ifsz...."); // Skip here all "()[]" etc
if( !s )
return NULL; // and print an error
if(!BuildValueCheck(s, v1))
return NULL; // and also print an error
return Py_BuildValue(format, v1);
}
template<typename t1, typename t2>
PyObject *BuildValue(char * format, t1 v1, t2 v2)
{
// Skip here all "()[]" etc
char * s = strchr(format, "ifsz....");
if( !s )
return NULL;
if(!BuildValueCheck(s, v1))
return NULL;
s = strchr(s+1, "ifsz....");
if( !s )
return NULL;
if(!BuildValueCheck(s, v2))
return NULL;
return Py_BuildValue(format, v1, v2);
}
// and so on for 3,4,5 params - I doubt your program uses more
// and then replace all Py_BuildValue with BuildValue across the code, or make a #define