Reputation: 305
If the argument list is empty
#define key_evaluate(r, key, sig) key |= 1 << sig;
#define getKey(...)\
({\
ComponentKey key = 0;\
BOOST_PP_SEQ_FOR_EACH(key_evaluate, key, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
key;\
})
int main(void)
{
getKey();
}
expands to
int main(void)
{
({
ComponentKey key = 0;
key |= 1 << ;
key;
})
}
but I would like to have it expand to nothing if _VA_ARGS_ is empty. This answers a question of this type, but if I use this instead
#define key_evaluate(r, key, sig) key |= 1 << sig;
#define convertToKey(...) BOOST_PP_SEQ_FOR_EACH(key_evaluate, key, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
#define components_convertToKey(...)\
({\
ComponentKey key = 0;\
BOOST_PP_IF(BOOST_PP_EQUAL(BOOST_PP_TUPLE_SIZE((,##__VA_ARGS__)), 1), \
BOOST_PP_EXPAND, convertToKey) (__VA_ARGS__) \
key;\
})
I get this error: error: ‘BOOST_PP_EXPAND’ undeclared
.
This means BOOST_PP_EXPAND is not replaced by the Preprocessor, because BOOST_PP_EXPAND is used elsewhere, which means it is defined.
Upvotes: 1
Views: 263
Reputation: 393174
I don't know.
I DO know
It looks like you're trying to combine a number of integral sigs into a key mask, so making up an example could look like:
enum SigKeys {
key0 = 1,
key1 = 2,
key2 = 4,
key3 = 8,
key4 = 16,
};
#include <iostream>
int main(void) {
std::cout << "key1, key2: " << (key1 + key2) << " == " << getKey(1, 2) << "\n";
std::cout << "key2, key4: " << (key2 + key4) << " == " << getKey(4, 2) << "\n";
}
Prints
key1, key2: 6 == 6
key2, key4: 20 == 20
Assuming your compiler is up to snuff, you could simply write that as:
template <typename... T>
constexpr ComponentKey getKey(T&&... sig) {
return (0 | ... | (1 << sig));
}
It will be standard, portable, compile in a fraction of the time, be more readable, contexpr and optimizable.
See it Live On Coliru
Even then you can have it better:
ComponentKey getKey(std::initializer_list<int> sig) {
return std::accumulate(sig.begin(), sig.end(), 0,
[](int r, int s) { return r | (1 << s); });
}
See it Live On Coliru as well. Unsurprisingly it will optimize just the same.
If you prefer without
std::accumulate
: Coliru and Compiler ExplorerComponentKey getKey(std::initializer_list<int> sig) { ComponentKey r = 0; for (auto& s : sig) r |= 1 << s; return r; }
Upvotes: 1