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__)) \
}};
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.
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.
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)?
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.