Converting a MPL Vector to a Static Array - c++

I wrote some code to generate a boost::mpl::vector to use as a lookup table for a factorial function, as a test for a more general library function with which a developer may be able to generate a lookup table in the form of a static array of primitives. The function (which would most probably be implemented as a preprocessor macro definition) would accept the name and size of the array to be initialized, as well the name of a class template to be used as the metafunction to initialize each element i of the array.
I thought that the best way to go about doing this without the use of external scripts would be to
Create a boost::mpl::vector, as is done in the code listing below, and push the return value of the user-supplied metafunction for each element of the array to the back of the vector;
Use the elements of the vector initialize the static array (perhaps by using a series of macros, the last of which would use the __VARARGS__ macro to accomplish this).
I know neither how I would accomplish (2) nor whether the procedure I describe is a good way of doing what I seek. Here are the following questions for which I would like answers:
Is my procedure a good way of accomplishing what I seek? If not, please describe a better procedure which would accomplish the same thing, without the use of external scripts.
If my procedure is indeed a good way of accomplishing what I seek, how would I implement (2)?
I will be sure to post a link to the source file containing library function which I describe once I implement it. The code listing follows below.
namespace mpl = boost::mpl;
template <typename x>
struct factorial:
mpl::if_<mpl::greater<x, mpl::int_<1>>,
mpl::multiplies<x, factorial<x::prior>>,
mpl::int_<1>
>::type
{};
template <typename sequence, typename size>
struct compileTable:
mpl::if_<mpl::greater<size, mpl::int_<0>>,
compileTable<
mpl::push_front<sequence, factorial<size>>::type,
size::prior
>,
sequence
>::type
{};
static const int TABLE_SIZE = 13;
typedef compileTable<
mpl::vector<>,
mpl::int_<TABLE_SIZE>
>::type factorialTable;
/*
** This is where I am stuck; how would I use the elements
** of factorialTable to initialize a static array?
*/

http://www.boost.org/doc/libs/1_46_0/libs/preprocessor/doc/index.html
#define MACRO(z, i, data) \
mpl::at_c<data,i>::value
static const data[] = { BOOST_PP_ENUM(N, MACRO, factorialTable) };

Here is the source code for the file containing the library function, as promised; please be sure to read the remarks I have made below the code listings. Thanks again to aaa for his help in showing me how to initialize a static array using BOOST_PP_ENUM!
Source code for xi/mpl/lut.h:
#ifndef __XI_LUT_INCLUDED__
#define __XI_LUT_INCLUDED__
#ifndef __cplusplus
#error The file __FILE__ requires a C++ compiler in order to be successfully compiled.
#endif
#include <boost/mpl/apply.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/greater.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/multiplies.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#define __XI_LUT_SET_INDEX(z, n, sequence) \
mpl::at_c<sequence, n>::type::value
#define __XI_GENERATE_LUT_IMPL(function, tableType, tableName, tableSize) \
\
template <typename sequence, typename size> \
struct __compileTable_##function##_##tableSize##: \
mpl::if_<mpl::greater<size, mpl::int_<0>>, \
__compileTable_##function##_##tableSize##< \
mpl::push_front<sequence, \
mpl::apply< \
function##<mpl::_>, \
size \
>::type>::type, \
size::prior \
>, \
sequence \
>::type \
{}; \
\
typedef __compileTable_##function##_##tableSize##< \
mpl::vector<>, \
mpl::int_<##tableSize##> \
>::type __compiledTable_##function##_##tableSize##; \
\
static const tableType tableName##[] = { \
BOOST_PP_ENUM( \
tableSize##, \
__XI_LUT_SET_INDEX, \
__compiledTable_##function##_##tableSize## \
) \
}
#define XI_GENERATE_LUT(function, tableType, tableName, tableSize) \
__XI_GENERATE_LUT_IMPL(function, tableType, tableName, tableSize)
#endif
Source code for a useful test file:
#include <boost/mpl/greater.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/multiplies.hpp>
#include <boost/mpl/placeholders.hpp>
#include <cstdio>
#include <xi/mpl/lut.hpp>
namespace mpl = boost::mpl;
template <typename x>
struct factorial:
mpl::if_<mpl::greater<x, mpl::int_<1>>,
mpl::multiplies<x, factorial<x::prior>>,
mpl::int_<1>
>::type
{};
XI_GENERATE_LUT(factorial, int, FACTORIAL_TABLE, 4);
int main(int argc, char ** argv) {
// This should print '24:'
printf("Result: %d.\n", FACTORIAL_TABLE[3]);
return 0;
}
I will refrain from providing a URL to the file for now so that I can continue to edit the code listing. I am confident that the code can be improved for purposes of compatibility, so it is definitely not in a final state. Here are some known issues:
The code will not compile on MSVC 9.0.
Attempting to create a lookup table of a particular size for a metafunction name after one has already been created of the same size and for the same metafunction name will result in an error, since corresponding types and templates would be defined for these parameters. I do not want to use __COUNTER__ to alleviate this problem since it is a nonstandard macro definition.
I have not tried compiling this code on any other compilers except ICC and MSCV, and would like to know how GCC handles it - please let me know of any issues which arise so that proper recourse may be taken. I will post a URL to the file once the code works with little trouble on most major compilers. Any feedback would be greatly appreciated!

Related

Preprocessor initialize array

How, if necessary, using boost preprocessor, initialize the array as follows:
INIT_ARRAY(plus,minus)
//extract to
std::array<std::pair<char const *,std::string>, 2> array{{
{"plus", std::string("plus")}, {"minus", std::string("minus")} }};
INIT_ARRAY(plus,minus,multiply)
//extract to
std::array<std::pair<char const *,std::string>, 3> array{{
{"plus", std::string("plus")}, {"minus", std::string("minus")}, {"multiply", std::string("multiply")} }};
P.S. Couldn't solve the problem with the last comma in the initializer (...{n-1} , {n} ,)
and counting the number of arguments to pass to std::array<...,n>. I use the preprocessor, since the names passed to the macro will be used later for code generation. Used c++20
You can use BOOST_PP_COMMA_IF for conditional commas, and BOOST_PP_VARIADIC_SIZE to work out the size beforehand.
This should work (for non-empty arrays):
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/variadic/size.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>
#define INIT_ARRAY_INITIALIZER(r, _, i, e) BOOST_PP_COMMA_IF(i) {BOOST_PP_STRINGIZE(e), std::string(BOOST_PP_STRINGIZE(e))}
#define INIT_ARRAY(...) \
std::array<std::pair<char const *, std::string>, \
BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)> array{{ \
BOOST_PP_SEQ_FOR_EACH_I(INIT_ARRAY_INITIALIZER, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
}};

BOOST_PP expand sequence in the empty sequence case

Using BOOST_PP I can expand a macro into multiple comma separated values with an additional token, as can be seen in the below code.
However, it doesn't work in the no-argument case.
#define BOOST_PP_VARIADICS
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>
#define ADD_TOKEN(r, token, i, e) \
BOOST_PP_COMMA_IF(i) token(e)
#define WRAP(...) \
BOOST_PP_SEQ_FOR_EACH_I(ADD_TOKEN, decltype, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
#define MACRO(fmt, ...) \
Template<WRAP(__VA_ARGS__)>
MACRO("");
MACRO("", 0);
MACRO("", 0, 1);
The output when compiling with gcc -E main.cpp is
Template< decltype() >;
Template< decltype(0) >;
Template< decltype(0) , decltype(1) >;
How can I get calls to MACRO with no __VA_ARGS__ arguments expand to null?
That is, I'd like the output to be:
Template< >;
Template< decltype(0) >;
Template< decltype(0) , decltype(1) >;
How can I achieve this?
This answer uses a GNU extension. You stated in the comments that you're okay with that.
You can use BOOST_PP_TUPLE_SIZE((, ## __VA_ARGS__)): it will give you 1 if and only if the variadic arguments are omitted.
Templates are a bit tricky in that they can contain unparenthesised commas, which cause confusion when used in macro arguments. It takes a bit of work to write it in such a way that the WRAP macro is only expanded after BOOST_PP_IF has finished already:
#define MACRO(fmt, ...) \
Template< \
BOOST_PP_IF(BOOST_PP_EQUAL(BOOST_PP_TUPLE_SIZE((,##__VA_ARGS__)), 1), \
BOOST_PP_EXPAND, WRAP) (__VA_ARGS__) \
>
Note: I'm using BOOST_PP_EXPAND in the empty case, because BOOST_PP_EXPAND(__VA_ARGS__) will expand to nothing.

Force compilation to fail if a struct member with a particular name exists

Suppose bad_name is a restricted identifier for example that I do not want to be part of the struct. I am looking for a mechanism to force a compilation failure in that case.
example.h
struct example {
int okay_name;
int bad_name;
}
main.cc
#include "example.h"
int main() {
example ex;
// cause compilation to fail here if bad_name is a member of ex
return 0;
}
There are probably ways to cause a failure at runtime by simulating reflection, but is there a way to do this at compile time?
You can define bad_name to be something that would cause a compile time error. For example, nothing:
#define bad_name
gives on GCC
error: declaration does not declare anything [-fpermissive]
int bad_name;
You can simulate static assertions in C like this:
#define bad_name xxx; char static_assertion_bad_name_used[-1];
struct example {
int okay_name;
int bad_name;
};
which in GCC gives:
main.c:6: error: size of array ‘static_assertion_bad_name_used’ is negative
The advantage of this technique is that the error message gives you a reminder of what the problem is (even if slightly obscurely).
Update After reading this I found out that MS Visual Studio does not include the actual variable name in the error message if the array size is negative. Here is an alternative:
#define bad_name xxx; int static_assertion_bad_name_used : 0;
The error message in GCC is then:
main.c:5: error: zero width for bit-field ‘static_assertion_bad_name_used’
and apparently something similar in VS.
Also if using a more up to date compiler you can use _Static_assert, which would be a lot cleaner.
You may use the following:
#include <cstdint>
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template <typename U> \
class traitsName \
{ \
private: \
template<typename T, T> struct helper; \
template<typename T> \
static std::uint8_t check(helper<signature, &funcName>*); \
template<typename T> static std::uint16_t check(...); \
public: \
static \
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
}
DEFINE_HAS_SIGNATURE(has_bad_name, T::bad_name, decltype(&T::bad_name));
Then check with a static_assert (need C++11):
static_assert(!has_bad_name<example>::value, "");
Suppose bad_name is a restricted identifier for example that I do not
want to be part of the struct. I am looking for a mechanism to force a
compilation failure in that case.
This is not fully portable, but at least in VC++ and GCC you can mark the identifier as deprecated and, if you want, elevate the warning it gives to an error.

How to tag some types to build a type list from these tagged types at compile time?

I generated some types with an external tool. I include some of them depending on the application. I tried to play with both boost preprocessor and boost mpl to tag my generated types and build an mpl vector of these tagged types.
Unfortunately, my trick only works when I am including the headers I need in a single file with my TypeRegistry.
// TypeRegistry.h
typedef ::boost::mpl::vector<> TypeRegistryRegisteredTypes0;
# define TYPE_REGISTRY_REGISTER_TYPE(T) \
typedef ::boost::mpl::push_back< \
BOOST_PP_CAT( \
TypeRegistryRegisteredTypes, \
BOOST_PP_COUNTER \
), \
##T \
>::type \
BOOST_PP_CAT(TypeRegistryRegisteredTypes, BOOST_PP_ADD(BOOST_PP_COUNTER,1))
# define TYPE_REGISTRY_SYNC_REGISTERED_TYPES() \
typedef BOOST_PP_CAT( \
TypeRegistryRegisteredTypes, \
BOOST_PP_COUNTER \
) TypeRegistryRegisteredTypes
template
<
class RegisteredTypesBase,
class RegisteredTypesVector
>
class TypeRegistry { ... };
This is the macro I use to register a type.
// A.h
class A : public IBase { ... };
TYPE_REGISTRY_REGISTER_TYPE(A);
#include BOOST_PP_UPDATE_COUNTER()
Here we are, in a source file, say main.h:
#include "TypeRegistry.h"
#include "A.h"
#include "B.h"
#include "C.h"
...
TYPE_REGISTRY_SYNC_REGISTERED_TYPES();
TypeRegistry< IBase, TypeRegistryRegisteredTypes > typeRegistry;
auto a = typeRegistry.instanceFromName("A");
auto b = typeRegistry.instanceFromName("B");
auto c = typeRegistry.instanceFromName("C");
As I said, the trick only works because I am including all my interesting types --so to say-- at the same time.
How would you perform an automatic type recording without having to include them all in a single file (that is, compiling a source file which is including its header file should be sufficient)?

Syntax Error in Preprocessor Macro Code

I am trying to write some code for a macro which returns the length of a string, and am attempting to implement it using BOOST_PP_WHILE. The code stems from the fact that a character at a position specified by position of the string represented by a macro argument foo may be obtained by #foo[position]. Compiling using either MSVC or Intel C++ results in similar syntax errors; if you could point out why the code is generating these syntax errors and how I would rectify code, it would be greatly appreciated. I know that the errors are caused by the code within the PREDICATE macro, but any expression I attempt to use within it barring BOOST_PP_TUPLE_ELEM results in a compile-time error.
Errors:
prog.cpp:47:1: error: pasting "BOOST_PP_BOOL_" and ""\"Hello, World!\""" does not give a valid preprocessing token
prog.cpp: In function ‘int main(int, char**)’:
prog.cpp:47: error: ‘BOOST_PP_TUPLE_ELEM_2_1’ was not declared in this scope
As one would expect, the line numbers are not very useful since both point to the line at which the macro MACRO_STRLEN is called.
Code
Below follows the source listing in which I attempt to implement the macro which I describe.
#include <boost/preprocessor/arithmetic/dec.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/comparison/equal.hpp>
#include <boost/preprocessor/control/while.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <cstdio>
#define TEST_STRING0 "Hello, World!"
#define MACRO_IS_NULL_IMPL(x, position) \
#x[position] == '\0'
#define MACRO_IS_NULL(x, position) \
MACRO_IS_NULL_IMPL(x, position)
#define PREDICATE_D(string, position) \
MACRO_IS_NULL(string, position)
#define PREDICATE(n, state) \
PREDICATE_D( \
BOOST_PP_TUPLE_ELEM(2, 0, state), \
BOOST_PP_TUPLE_ELEM(2, 1, state) \
)
#define OPERATION_D(string, position) \
( \
string, \
BOOST_PP_INC(position) \
)
#define OPERATION(d, state) \
OPERATION_D( \
BOOST_PP_TUPLE_ELEM(2, 0, state), \
BOOST_PP_TUPLE_ELEM(2, 1, state) \
)
#define MACRO_STRLEN_IMPL(string) \
BOOST_PP_TUPLE_ELEM( \
2, 1, BOOST_PP_WHILE(PREDICATE, OPERATION, (string, 0)) \
)
#define MACRO_STRLEN(string) \
MACRO_STRLEN_IMPL(string)
int main(int argc, char ** argv) {
printf("String length: %d.\n", MACRO_STRLEN(TEST_STRING0));
return 0;
}
How about this - http://codepad.org/aT7SK1Lu
Its still a compile-time strlen, and would be likely much faster to compile.
#include <stdio.h>
#include <string.h>
#define TEST_STRING "Hello, World!"
template <int N> struct xtmp2 { typedef char (&t)[N]; };
template< class T, int N > typename xtmp2<N>::t xlen( T (&)[N] );
#define STRLEN(x) (sizeof(xlen(x))-1)
int main( void ) {
printf( "strlen(\"%s\") = %i %i\n", TEST_STRING, STRLEN(TEST_STRING), strlen(TEST_STRING) );
}
As to macro debug, its possible to get a preprocessor output (like gcc -E);
it may be also helpful to undefine most macros, then enable them one by one to
see what happens.
Please forgive me if this is an irrelevant pointing out.
The predicate for BOOST_PP_WHILE is evaluated while preprocess.
However, if I understand correctly, MACRO_IS_NULL_IMPL determines whether
the character is '\0' at compile-time(runtime?).
So, I think it is difficult to accomplish the goal directly with string
literal "Hello, World!".
It won't work, and for a simple reason: the preprocessor is not meant to deal with literals.
The preprocessor only knows about "tokens", it can catenate them, it can transform one into a string literal, and it can operate macros replacements, but that's it.
Here, the condition to stop the loop (use of [] and ==) could be, at best, executed by the compiler (and most likely at runtime), therefore is not suitable for BOOST_PP_WHILE.
You can, actually, use the compiler to get the number of elements of an array (here an array of characters):
For example using sizeof: sizeof(array)/sizeof(array[0]). This can be abstracted in a macro, however it cannot become a "regular" function, since arrays cannot be passed to "regular" functions, only pointers (where you've lost the information size).
You can also use a template function:
template <typename T, size_t N>
size_t size(T (&)[N]) { return N; }
(this actually work on any array with a constant size)
But, for your own issue, you'll be pleased to know that most compilers have a built-in strlen implementation for constants that evaluates at compile-time.
I wonder if it was supposed to be something like this:
#include <stdio.h>
#include <string.h>
#define TEST_STRING "Hello, World!"
#define STRLEN(x) (x[0]==0)?0:TEST_01(x,1)
#define TEST_01(x,y) (x[y]==0)?y:TEST_02(x,y+1)
#define TEST_02(x,y) (x[y]==0)?y:TEST_03(x,y+1)
#define TEST_03(x,y) (x[y]==0)?y:TEST_04(x,y+1)
#define TEST_04(x,y) (x[y]==0)?y:TEST_05(x,y+1)
#define TEST_05(x,y) (x[y]==0)?y:TEST_06(x,y+1)
#define TEST_06(x,y) (x[y]==0)?y:TEST_07(x,y+1)
#define TEST_07(x,y) (x[y]==0)?y:TEST_08(x,y+1)
#define TEST_08(x,y) (x[y]==0)?y:TEST_09(x,y+1)
#define TEST_09(x,y) (x[y]==0)?y:TEST_10(x,y+1)
#define TEST_10(x,y) (x[y]==0)?y:TEST_11(x,y+1)
#define TEST_11(x,y) (x[y]==0)?y:TEST_12(x,y+1)
#define TEST_12(x,y) (x[y]==0)?y:TEST_13(x,y+1)
#define TEST_13(x,y) (x[y]==0)?y:TEST_14(x,y+1)
#define TEST_14(x,y) (x[y]==0)?y:TEST_15(x,y+1)
#define TEST_15(x,y) (x[y]==0)?y:TEST_16(x,y+1)
#define TEST_16(x,y) (x[y]==0)?y:TEST_17(x,y+1)
#define TEST_17(x,y) (x[y]==0)?y:TEST_18(x,y+1)
#define TEST_18(x,y) (x[y]==0)?y:TEST_19(x,y+1)
#define TEST_19(x,y) (x[y]==0)?y:-1
int main( void ) {
printf( "strlen(\"%s\") = %i %i\n", TEST_STRING, STRLEN(TEST_STRING), strlen(TEST_STRING) );
}
But this isn't a compile-time evaluation, even though it would be usually
optimized to a constant.