I've created a function declared as:
template <typename Container, typename Task>
void parallel_for_each(Container &container, Task task,
unsigned number_of_threads = std::thread::hardware_concurrency())
It's not difficult to guess what it is supposed to do. I'd like to create a macro simplifying the syntax of this function and making the its syntax "loop-like". I've come up with an idea:
#define in ,
#define pforeach(Z,X,Y) parallel_for_each(X,[](Z)->void{Y;})
Where usage as:
pforeach(double &element, vec,
{
element *= 2;
});
works as expected, but this one:
pforeach(double &element in vec,
{
element *= 2;
element /= 2;
});
gives an error
macro "pforeach" requires 3 arguments, but only 2 given
Do you have any idea how to write a macro allowing even "nicer" syntax? Why "in" doesn't stand for comma in my code?
The reason that in is not replaced is that it appears inside an argument to your function-like macro, but for it to be replaced, those arguments have to be propagated to another macro first: Try
#define in ,
#define pforeach_(Z,X,Y) parallel_for_each(X,[](Z)->void{Y;})
#define pforeach(Z,X,Y) pforeach_(Z,X,Y)
Note: Defining in as , is not gonna end well!
An idea to add "nicer" syntax:
template <typename Container>
struct Helper {
Container&& c;
template <typename Arg>
void operator=(Arg&& arg) {
parallel_for_each(std::forward<Container>(c), std::forward<Arg>(arg));
}
};
#define CONCAT_(a,b) a##b
#define CONCAT(a,b) CONCAT_(a,b)
// Easier with Boost.PP
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define DEC_6 5
#define DEC_7 6
#define DEC_8 7
#define DEC(i) CONCAT(DEC_,i)
#define pforeach(Z, ...) \
Helper<decltype((__VA_ARGS__))> CONCAT(_unused_obj, __COUNTER__){__VA_ARGS__}; \
CONCAT(_unused_obj, DEC(__COUNTER__))=[](Z)
Usable as
int a[] = {1, 2, 3};
pforeach(int i, a) {
std::cout << i << ", ";
};
pforeach(int i, std::vector<int>{1, 2, 3}) {
std::cout << -i << ", ";
};
Demo.
Has several disadvantages though. I'd just stick with what you've got so far.
Why "in" doesn't stand for comma in my code?
Because that replacement is performed after macro arguments are determined. Quoting standard draft N3797, § 16.3.1 Argument substitution:
After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. ... Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens
are available.
So preprocessor identifies pforeach(double &element in vec, {}) as a function-like macro call with two arguments:
First consists of tokens double, &, in and vec and bound to argument Z
Second consists of tokens { and } and bound to argument X
You're obviously miss argument Y
Do you have any idea how to write a macro allowing even "nicer" syntax?
It is hard to answer and it is matter of taste. Anyway, C++ has rich capabilities of patching syntax with operator overload, but you can't build DSL with that, so it is better to use default syntax, it is not that ugly (and also makes it easy to read):
parallel_for_each(vec, [](double& el){ el *= 2; })
There is no macro langugae. Macros are handled by the C/C++ preprocessor. The implementation of the preprocessors may vary.
Most preprocessors expect that you pass the exact number of parameters. I found that the GNU preprocessor has a less strict checking of parameters what allows a kind of variadic list. But in general a macro won't help you with your task.
I recommend to write the short statement in a function instead of a macro. An inline function is as fast and short as a macro, but type safe.
Further the function allows default parameter values. So you can skip something.
Trying to improve the idea of #Columbo :
template <typename Container>
struct __pforeach__helper {
Container &&c;
template <typename Arg>
void operator=(Arg&& arg) {
parallel_for_each(std::forward<Container>(c), std::forward<Arg>(arg));
}
};
//additional helper function
template <typename Container>
__pforeach__helper<Container> __create__pforeach__helper(Container &&c)
{
return __pforeach__helper<Container>(__pforeach__helper<Container>{c});
}
#define pforeach(Z,C) \
__create__pforeach__helper(C)=[](Z)
It doesn't rely on __COUNTER__ and doesn't require defining DEC_x macros. Any feedback is most welcome!
Related
I am currently working on a project, where every cycle counts. While profiling my application I discovered that the overhead of some inner loop is quite high, because they consist of just a few machine instruction. Additionally the number of iterations in these loops is known at compile time.
So I thought instead of manually unrolling the loop with copy & paste I could use macros to unroll the loop at compile time so that it can be easily modified later.
What I image is something like this:
#define LOOP_N_TIMES(N, CODE) <insert magic here>
So that I can replace for (int i = 0; i < N, ++i) { do_stuff(); } with:
#define INNER_LOOP_COUNT 4
LOOP_N_TIMES(INNER_LOOP_COUNT, do_stuff();)
And it unrolls itself to:
do_stuff(); do_stuff(); do_stuff(); do_stuff();
Since the C preprocessor is still a mystery to me most of the time, I have no idea how to accomplish this, but I know it must be possible because Boost seems to have a BOOST_PP_REPEAT macros. Unfortunately I can't use Boost for this project.
You can use templates to unroll.
See the disassembly for the sample Live on Godbolt
But -funroll-loops has the same effect for this sample.
Live On Coliru
template <unsigned N> struct faux_unroll {
template <typename F> static void call(F const& f) {
f();
faux_unroll<N-1>::call(f);
}
};
template <> struct faux_unroll<0u> {
template <typename F> static void call(F const&) {}
};
#include <iostream>
#include <cstdlib>
int main() {
srand(time(0));
double r = 0;
faux_unroll<10>::call([&] { r += 1.0/rand(); });
std::cout << r;
}
You can use the pre-processor and play some tricks with token concatenation and multiple macro expansion, but you have to hard-code all possibilities:
#define M_REPEAT_1(X) X
#define M_REPEAT_2(X) X X
#define M_REPEAT_3(X) X X X
#define M_REPEAT_4(X) X X X X
#define M_REPEAT_5(X) X M_REPEAT_4(X)
#define M_REPEAT_6(X) M_REPEAT_3(X) M_REPEAT_3(X)
#define M_EXPAND(...) __VA_ARGS__
#define M_REPEAT__(N, X) M_EXPAND(M_REPEAT_ ## N)(X)
#define M_REPEAT_(N, X) M_REPEAT__(N, X)
#define M_REPEAT(N, X) M_REPEAT_(M_EXPAND(N), X)
And then expand it like this:
#define THREE 3
M_REPEAT(THREE, three();)
M_REPEAT(4, four();)
M_REPEAT(5, five();)
M_REPEAT(6, six();)
This method requires literal numbers as counts, you can't do something like this:
#define COUNT (N + 1)
M_REPEAT(COUNT, stuff();)
There's no standard way of doing this.
Here's a slightly bonkers approach:
#define DO_THING printf("Shake it, Baby\n")
#define DO_THING_2 DO_THING; DO_THING
#define DO_THING_4 DO_THING_2; DO_THING_2
#define DO_THING_8 DO_THING_4; DO_THING_4
#define DO_THING_16 DO_THING_8; DO_THING_8
//And so on. Max loop size increases exponentially. But so does code size if you use them.
void do_thing_25_times(void){
//Binary for 25 is 11001
DO_THING_16;//ONE
DO_THING_8;//ONE
//ZERO
//ZERO
DO_THING;//ONE
}
It's not too much to ask of an optimizer to eliminate dead code.
In which case:
#define DO_THING_N(N) if(((N)&1)!=0){DO_THING;}\
if(((N)&2)!=0){DO_THING_2;}\
if(((N)&4)!=0){DO_THING_4;}\
if(((N)&8)!=0){DO_THING_8;}\
if(((N)&16)!=0){DO_THING_16;}
You can't use a #define construct to calculate the "unroll-count". But with sufficient macros you can define this:
#define LOOP1(a) a
#define LOOP2(a) a LOOP1(a)
#define LOOP3(a) a LOOP2(a)
#define LOOPN(n,a) LOOP##n(a)
int main(void)
{
LOOPN(3,printf("hello,world"););
}
Tested with VC2012
You can't write real recursive statements with macros and I'm pretty sure you can't have real iteration in macros as well.
However you can take a look at Order. Although it is entirely built atop the C preprocessor it "implements" iteration-like functionalities. It actually can have up-to-N iterations, where N is some large number. I'm guessing it's similar for "recursive" macros. Any way, it is such a borderline case that few compilers support it (GCC is one of them, though).
Is there a good pattern that will let me use templates to generate a precomputed array from a given an element type, desired length, and custom function f(int index)?
Consider this C-style implementation.
#define FORLIST_1(fOfi) (fOfi)(0)
#define FORLIST_2(fOfi) FORLIST_1(fOfi) , (fOfi)(1 )
#define FORLIST_3(fOfi) FORLIST_2(fOfi) , (fOfi)(2 )
#define FORLIST_4(fOfi) FORLIST_3(fOfi) , (fOfi)(3 )
//... And so on
// Toy example user-specified function which describes how to create the table
double genEntry(u32 i) {
return i == 0 ? 0 : std::log(i) / std::log(5);
}
// Generate a precomputed lookup table
// FORLIST_15 expands into genEntry(0), genEntry(1), genEntry(2), ...
const double lookupTable[16] = {
FORLIST_16(genEntry)
};
What is the cleanest way to do the same thing with templates? It has to allow me to specify the number of elements in the array and allow me to supply some kind of user function (index as the parameter). Functors, std::function, lambda, function pointer, etc, are probably all acceptable ways to define the element generator.
I will probably want to explicit-instantiate the template once into an obj/lib so that the table itself is only defined once ever, as a linkable symbol instead of being recompiled into each .cpp file that includes the header.
With variadic template, you may do something like:
template <typename F, std::size_t ... Is>
auto
make_array(F f, std::index_sequence<Is...>)
-> std::array<std::decay_t<decltype(f(0u))>, sizeof...(Is)>
{
return {{f(Is)...}};
}
Live demo.
Note: decay_t, index_sequence and make_index_sequence are C++14 but can be written in C++11.
I am currently working on a project, where every cycle counts. While profiling my application I discovered that the overhead of some inner loop is quite high, because they consist of just a few machine instruction. Additionally the number of iterations in these loops is known at compile time.
So I thought instead of manually unrolling the loop with copy & paste I could use macros to unroll the loop at compile time so that it can be easily modified later.
What I image is something like this:
#define LOOP_N_TIMES(N, CODE) <insert magic here>
So that I can replace for (int i = 0; i < N, ++i) { do_stuff(); } with:
#define INNER_LOOP_COUNT 4
LOOP_N_TIMES(INNER_LOOP_COUNT, do_stuff();)
And it unrolls itself to:
do_stuff(); do_stuff(); do_stuff(); do_stuff();
Since the C preprocessor is still a mystery to me most of the time, I have no idea how to accomplish this, but I know it must be possible because Boost seems to have a BOOST_PP_REPEAT macros. Unfortunately I can't use Boost for this project.
You can use templates to unroll.
See the disassembly for the sample Live on Godbolt
But -funroll-loops has the same effect for this sample.
Live On Coliru
template <unsigned N> struct faux_unroll {
template <typename F> static void call(F const& f) {
f();
faux_unroll<N-1>::call(f);
}
};
template <> struct faux_unroll<0u> {
template <typename F> static void call(F const&) {}
};
#include <iostream>
#include <cstdlib>
int main() {
srand(time(0));
double r = 0;
faux_unroll<10>::call([&] { r += 1.0/rand(); });
std::cout << r;
}
You can use the pre-processor and play some tricks with token concatenation and multiple macro expansion, but you have to hard-code all possibilities:
#define M_REPEAT_1(X) X
#define M_REPEAT_2(X) X X
#define M_REPEAT_3(X) X X X
#define M_REPEAT_4(X) X X X X
#define M_REPEAT_5(X) X M_REPEAT_4(X)
#define M_REPEAT_6(X) M_REPEAT_3(X) M_REPEAT_3(X)
#define M_EXPAND(...) __VA_ARGS__
#define M_REPEAT__(N, X) M_EXPAND(M_REPEAT_ ## N)(X)
#define M_REPEAT_(N, X) M_REPEAT__(N, X)
#define M_REPEAT(N, X) M_REPEAT_(M_EXPAND(N), X)
And then expand it like this:
#define THREE 3
M_REPEAT(THREE, three();)
M_REPEAT(4, four();)
M_REPEAT(5, five();)
M_REPEAT(6, six();)
This method requires literal numbers as counts, you can't do something like this:
#define COUNT (N + 1)
M_REPEAT(COUNT, stuff();)
There's no standard way of doing this.
Here's a slightly bonkers approach:
#define DO_THING printf("Shake it, Baby\n")
#define DO_THING_2 DO_THING; DO_THING
#define DO_THING_4 DO_THING_2; DO_THING_2
#define DO_THING_8 DO_THING_4; DO_THING_4
#define DO_THING_16 DO_THING_8; DO_THING_8
//And so on. Max loop size increases exponentially. But so does code size if you use them.
void do_thing_25_times(void){
//Binary for 25 is 11001
DO_THING_16;//ONE
DO_THING_8;//ONE
//ZERO
//ZERO
DO_THING;//ONE
}
It's not too much to ask of an optimizer to eliminate dead code.
In which case:
#define DO_THING_N(N) if(((N)&1)!=0){DO_THING;}\
if(((N)&2)!=0){DO_THING_2;}\
if(((N)&4)!=0){DO_THING_4;}\
if(((N)&8)!=0){DO_THING_8;}\
if(((N)&16)!=0){DO_THING_16;}
You can't use a #define construct to calculate the "unroll-count". But with sufficient macros you can define this:
#define LOOP1(a) a
#define LOOP2(a) a LOOP1(a)
#define LOOP3(a) a LOOP2(a)
#define LOOPN(n,a) LOOP##n(a)
int main(void)
{
LOOPN(3,printf("hello,world"););
}
Tested with VC2012
You can't write real recursive statements with macros and I'm pretty sure you can't have real iteration in macros as well.
However you can take a look at Order. Although it is entirely built atop the C preprocessor it "implements" iteration-like functionalities. It actually can have up-to-N iterations, where N is some large number. I'm guessing it's similar for "recursive" macros. Any way, it is such a borderline case that few compilers support it (GCC is one of them, though).
Here is my source (as answer) , how to implement underlying_value, and to_enum functions.
How to automatically convert strongly typed enum into int?
underlying_value - no problem.
but, to_enum - has problem.
see:
enum class E{ a = 1, b = 3, c = 5 };
auto e_a = utils::underlying_value(E::a); //OK
E t = utils::to_enum<E>( 2 ) ; // compiled, but it's incorrect. I think here must throws exception?
Q: how to implement to_enum correctly?
Despite the comments on the question, this can be done in C++11, though to do it without code repetition you will eventually have to wrap the enum class declaration in a macro. That may make my answer unsuitable, depending on your needs. Either way, doing the checked conversion requires some machinery, so I will get to the macro last.
The basic idea is to use constexpr functions to scan an array:
#include <iostream>
#include <stdexcept>
enum class E { a = 1, b = 3, c = 5 };
constexpr E values[] = {E::a, E::b, E::c};
constexpr size_t count = sizeof(values) / sizeof(E);
constexpr E to_enum(int value, size_t index = 0)
{
return
index >= count ? throw std::runtime_error("invalid integer") :
static_cast<int>(values[index]) == value ? values[index] :
to_enum(value, index + 1);
}
constexpr E converted = to_enum(3);
// Will not compile if uncommented.
// constexpr E bad_converted = to_enum(2);
int main()
{
std::cout << static_cast<int>(converted) << std::endl;
return 0;
}
This prints 3. If the line with bad_converted is uncommented, this code will not compile at all, as it says. The checked conversion can be done either at runtime or during compilation. It will be done during compilation if the argument to to_enum is a compile-time constant. Also, as you can probably see, this does a linear scan of values, but that can be replaced with another algorithm if it becomes a performance problem for a very large enum.
The code I just showed is a sketch that shows the underlying method. In order to make this less of a pain to use, you should wrap the declaration of E in a macro that will automatically generate the values[] array and the associated functions. I will show and rationalize the contents of this macro one point at a time.
The basic macro looks like this
// Declaration header
#define ENUM_CLASS(TypeName, __VA_ARGS__)
// Use
ENUM_CLASS(E, a = 1, b = 3, c = 5);
So, in this example, __VA_ARGS__ will be the tokens a = 1, b = 3, c = 5. So, we can declare the enum itself inside the macro as follows:
enum class TypeName { __VA_ARGS__ };
However, we cannot simply declare:
constexpr TypeName values[] = { __VA_ARGS__ };
because that expands to
constexpr TypeName values[] = { a = 1, b = 3, c = 5 };
which is not scoped (missing TypeName:: in front of each value), and is not valid C++ because of the extra assignment operators inside the array initializer. I will solve the second problem first. You need to define a class like this one:
template <typename E>
class swallow_assignment {
public:
E _value;
constexpr explicit swallow_assignment(E value) : _value(value)
{
}
template <typename Any>
constexpr const swallow_assignment& operator =(Any other) const
{
return *this;
}
constexpr operator E() const
{
return _value;
}
};
Now, you can write (swallow_assignment<E>)E::a = 1. What will happen is, at compile time, E::a will get converted to the assignable value (swallow_assignment<E>)E::a, which has the same internal representation as E::a. That value will then ignore the assignment of 1, and then will be converted back to E::a.
What's left is to prefix each of the declared constants so that we get
constexpr TypeName values[] =
{(swallow_assignment<E>)E::a = 1,
(swallow_assignment<E>)E::b = 3,
(swallow_assignment<E>)E::c = 5})
which will now be a valid initializer. This can be done with a mapping macro. I won't go into the details here, because that is a whole separate topic, but such a macro can be found here https://github.com/aantron/better-enums/blob/e28177b11a9e3d7152c5216d84fdf8939aff0eba/enum_preprocessor_map.h. Boost might also have a better one. Whatever macro you are using, I will assume that its signature is PP_MAP(prefix, __VA_ARGS__). The sketch for the final macro definition for the whole enum then becomes:
#define ENUM_CLASS(TypeName, __VA_ARGS__) \
enum class TypeName { __VA_ARGS__ }; \
constexpr TypeName values[] = \
{ PP_MAP((swallow_assignment<TypeName>)TypeName::, \
__VA_ARGS__) }; \
constexpr size_t count = sizeof(values) / sizeof(TypeName);
You will probably want to stuff these definitions into a specialization of a traits type, so that you can use this macro with more than one enum class (otherwise the arrays named values will collide). You may have to use weak symbols to avoid linking problems if you make values a static member of a traits class, however.
These last points are left as an exercise, because this answer is already way too long :) I have a library which does all of the above, though it wraps an enum instead of providing a traits specialization for an enum class. There is an unpublished branch with a combination of enum class/traits, however. You can see the library here: http://aantron.github.io/better-enums. The library's ::_from_integral() method corresponds to the to_enum function in your question, and it does both run-time and compile-time conversions.
I have a C++ expression that I wish to 'freeze'. By this, I mean I have syntax like the following:
take x*x with x in container ...
where the ... indicates further (non-useful to this problem) syntax. However, if I attempt to compile this, no matter what preprocessor translations I've used to make 'take' an 'operator' (in inverted commas because it's technically not an operator, but the translation phase turns it into a class with, say, operator* available to it), the compiler still attempts to evaluate / work out where the x*x is coming from, (and, since it hasn't been declared previously (as it's declared further at the 'in' stage), it instead) can't find it and throws a compile error.
My current idea essentially involves attempting to place the expression inside a lambda (and since we can deduce the type of the container, we can declare x with the right type as, say, [](decltype(*begin(container)) x) { return x*x } -- thus, when the compiler looks at this statement, it's valid and no error is thrown), however, I'm running into errors actually achieving this.
Thus, my question is:
Is there a way / what's the best way to 'freeze' the x*x part of my expression?
EDIT:
In an attempt to clarify my question, take the following. Assume that the operator- is defined in a sane way so that the following attempts to achieve what the above take ... syntax does:
MyTakeClass() - x*x - MyWithClass() - x - MyInClass() - container ...
When this statement is compiled, the compiler will throw an error; x is not declared so x*x makes no sense (nor does x - MyInClass(), etc, etc). What I'm trying to achieve is to find a way to make the above expression compile, using any voodoo magic available, without knowing the type of x (or, in fact, that it will be named x; it could viably be named 'somestupidvariablename') in advance.
I came up with an almost solution, based on expression templates (note: these are not expression templates, they are based on expression templates). Unfortunately, I could not come up with a way that does not require you to predeclare x, but I did come up with a way to delay the type, so you only have to declare x one globally, and can use it for different types over and over in the same program/file/scope. Here is the expression type that works the magic, which I designed to be very flexible, you should be able to easily add operations and uses at will. It is used exactly how you described, except for the predeclaration of x.
Downsides I'm aware of: it does require T*T, T+T, and T(long) be compilable.
expression x(0, true); //x will be the 0th parameter. Sorry: required :(
int main() {
std::vector<int> container;
container.push_back(-3);
container.push_back(0);
container.push_back(7);
take x*x with x in container; //here's the magic line
for(unsigned i=0; i<container.size(); ++i)
std::cout << container[i] << ' ';
std::cout << '\n';
std::vector<float> container2;
container2.push_back(-2.3);
container2.push_back(0);
container2.push_back(7.1);
take 1+x with x in container2; //here's the magic line
for(unsigned i=0; i<container2.size(); ++i)
std::cout << container2[i] << ' ';
return 0;
}
and here's the class and defines that makes it all work:
class expression {
//addition and constants are unused, and merely shown for extendibility
enum exprtype{parameter_type, constant_type, multiplication_type, addition_type} type;
long long value; //for value types, and parameter number
std::unique_ptr<expression> left; //for unary and binary functions
std::unique_ptr<expression> right; //for binary functions
public:
//constructors
expression(long long val, bool is_variable=false)
:type(is_variable?parameter_type:constant_type), value(val)
{}
expression(const expression& rhs)
: type(rhs.type)
, value(rhs.value)
, left(rhs.left.get() ? std::unique_ptr<expression>(new expression(*rhs.left)) : std::unique_ptr<expression>(NULL))
, right(rhs.right.get() ? std::unique_ptr<expression>(new expression(*rhs.right)) : std::unique_ptr<expression>(NULL))
{}
expression(expression&& rhs)
:type(rhs.type), value(rhs.value), left(std::move(rhs.left)), right(std::move(rhs.right))
{}
//assignment operator
expression& operator=(expression rhs) {
type = rhs.type;
value = rhs.value;
left = std::move(rhs.left);
right = std::move(rhs.right);
return *this;
}
//operators
friend expression operator*(expression lhs, expression rhs) {
expression ret(0);
ret.type = multiplication_type;
ret.left = std::unique_ptr<expression>(new expression(std::move(lhs)));
ret.right = std::unique_ptr<expression>(new expression(std::move(rhs)));
return ret;
}
friend expression operator+(expression lhs, expression rhs) {
expression ret(0);
ret.type = addition_type;
ret.left = std::unique_ptr<expression>(new expression(std::move(lhs)));
ret.right = std::unique_ptr<expression>(new expression(std::move(rhs)));
return ret;
}
//skip the parameter list, don't care. Ignore it entirely
expression& operator<<(const expression&) {return *this;}
expression& operator,(const expression&) {return *this;}
template<class container>
void operator>>(container& rhs) {
for(auto it=rhs.begin(); it!=rhs.end(); ++it)
*it = execute(*it);
}
private:
//execution
template<class T>
T execute(const T& p0) {
switch(type) {
case parameter_type :
switch(value) {
case 0: return p0; //only one variable
default: throw std::runtime_error("Invalid parameter ID");
}
case constant_type:
return ((T)(value));
case multiplication_type:
return left->execute(p0) * right->execute(p0);
case addition_type:
return left->execute(p0) + right->execute(p0);
default:
throw std::runtime_error("Invalid expression type");
}
}
//This is also unused, and merely shown as extrapolation
template<class T>
T execute(const T& p0, const T& p1) {
switch(type) {
case parameter_type :
switch(value) {
case 0: return p0;
case 1: return p1; //this version has two variables
default: throw std::runtime_error("Invalid parameter ID");
}
case constant_type:
return value;
case multiplication_type:
return left->execute(p0, p1) * right->execute(p0, p1);
case addition_type:
return left->execute(p0, p1) + right->execute(p0, p1);
default:
throw std::runtime_error("Invalid expression type");
}
}
};
#define take
#define with <<
#define in >>
Compiles and runs with correct output at http://ideone.com/Dnb50
You may notice that since the x must be predeclared, the with section is ignored entirely. There's almost no macro magic here, the macros effectively turn it into "x*x >> x << container", where the >>x does absolutely nothing at all. So the expression is effectively "x*x << container".
Also note that this method is slow, because this is an interpreter, with almost all the slowdown that implies. However, it has the bonus that it is serializable, you could save the function to a file, load it later, and execute it then.
R.MartinhoFernandes has observed that the definition of x can be simplified to merely be expression x;, and it can deduce the order of parameters from the with section, but it would require a lot of rethinking of the design and would be more complicated. I might come back and add that functionality later, but in the meantime, know that it is definitely possible.
If you can modify the expression to `take(x*x with x in container)`, than that would remove the need to predeclare `x`, with something far far simpler than expression templates.
#define with ,
#define in ,
#define take(expr, var, con) \
std::transform(con.begin(), con.end(), con.begin(), \
[](const typename con::value_type& var) -> typename con::value_type \
{return expr;});
int main() {
std::vector<int> container;
container.push_back(-3);
container.push_back(0);
container.push_back(7);
take(x*x with x in container); //here's the magic line
for(unsigned i=0; i<container.size(); ++i)
std::cout << container[i] << ' ';
}
I made an answer very similar to my previous answer, but using actual expression templates, which should be much faster. Unfortunately, MSVC10 crashes when it attempts to compile this, but MSVC11, GCC 4.7.0 and Clang 3.2 all compile and run it just fine. (All other versions untested)
Here's the usage of the templates. Implementation code is here.
#define take
#define with ,
#define in >>=
//function call for containers
template<class lhsexpr, class container>
lhsexpr operator>>=(lhsexpr lhs, container& rhs)
{
for(auto it=rhs.begin(); it!=rhs.end(); ++it)
*it = lhs(*it);
return lhs;
}
int main() {
std::vector<int> container0;
container0.push_back(-4);
container0.push_back(0);
container0.push_back(3);
take x*x with x in container0; //here's the magic line
for(auto it=container0.begin(); it!=container0.end(); ++it)
std::cout << *it << ' ';
std::cout << '\n';
auto a = x+x*x+'a'*x;
auto b = a; //make sure copies work
b in container0;
b in container1;
std::cout << sizeof(b);
return 0;
}
As you can see, this is used exactly like my previous code, except now all the functions are decided at compile time, which means this will have exactly the same speed as a lambda. In fact, C++11 lambdas were preceeded by boost::lambda which works on very similar concepts.
This is a separate answer, because the code is far different, and far more complicated/intimidating. That's also why the implementation is not in the answer itself.
I don't think it is possible to get this "list comprehesion" (not quite, but it is doing the same thing) ala haskell using the preprocessor. The preprocessor just does simple search and replace with the possibility of arguments, so it cannot perform arbitrary replacements. Especially changing the order of parts of expression is not possible.
I cannot see a way to do this, without changing the order, since you always need x somehow to appear before x*x to define this variable. Using a lambda will not help, since you still need x in front of the x*x part, even if it is just as an argument. This makes this syntax not possible.
There are some ways around this:
Use a different preprocessor. There are preprocessors based on the ideas of Lisp-macros, which can be made syntax aware and hence can do arbitrary transformation of one syntax tree into another. One example is Camlp4/Camlp5 developed for the OCaml language. There are some very good tutorials on how to use this for arbitrary syntax transformation. I used to have an explanation on how to use Camlp4 to transform makefiles into C code, but I cannot find it anymore. There are some other tutorials on how to do such things.
Change the syntax slightly. Such list comprehension is essientially just a syntactic simplification of the usage of a Monad. With the arrival of C++11 Monads have become possible in C++. However the syntactic sugar may not be. If you decide to wrap the stuff you are trying to do in a Monad, many things will still be possible, you will just have to change the syntax slightly. Implementing Monads in C++ is anything but fun though (although I first expected otherwise). Have a look here for some example how to get Monads in C++.
The best approach is to parse it using the preprocessor.I do believe the preprocessor can be a very powerful tool for building EDSLs(embedded domain specific languages), but you must first understand the limitations of the preprocessor parsing things. The preprocessor can only parse out predefined tokens. So the syntax must be changed slightly by placing parenthesis around the expressions, and a FREEZE macro must surround it also(I just picked FREEZE, it could be called anything):
FREEZE(take(x*x) with(x, container))
Using this syntax you can convert it to a preprocessor sequence(using the Boost.Preprocessor library, of course). Once you have it as a preprocessor sequence you can apply lots of algorithms to it to transform it to however you like. A similiar approach is done with the Linq library for C++, where you can write this:
LINQ(from(x, numbers) where(x > 2) select(x * x))
Now, to convert to a pp sequence first you need to define the keywords to be parsed, like this:
#define KEYWORD(x) BOOST_PP_CAT(KEYWORD_, x)
#define KEYWORD_take (take)
#define KEYWORD_with (with)
So the way this will work is when you call KEYWORD(take(x*x) with(x, container)) it will expand to (take)(x*x) with(x, container), which is the first step towards converting it to a pp sequence. Now to keep going we need to use a while construct from the Boost.Preprocessor library, but first we need to define some little macros to help us along the way:
// Detects if the first token is parenthesis
#define IS_PAREN(x) IS_PAREN_CHECK(IS_PAREN_PROBE x)
#define IS_PAREN_CHECK(...) IS_PAREN_CHECK_N(__VA_ARGS__,0)
#define IS_PAREN_PROBE(...) ~, 1,
#define IS_PAREN_CHECK_N(x, n, ...) n
// Detect if the parameter is empty, works even if parenthesis are given
#define IS_EMPTY(x) BOOST_PP_CAT(IS_EMPTY_, IS_PAREN(x))(x)
#define IS_EMPTY_0(x) BOOST_PP_IS_EMPTY(x)
#define IS_EMPTY_1(x) 0
// Retrieves the first element of the sequence
// Example:
// HEAD((1)(2)(3)) // Expands to (1)
#define HEAD(x) PICK_HEAD(MARK x)
#define MARK(...) (__VA_ARGS__),
#define PICK_HEAD(...) PICK_HEAD_I(__VA_ARGS__,)
#define PICK_HEAD_I(x, ...) x
// Retrieves the tail of the sequence
// Example:
// TAIL((1)(2)(3)) // Expands to (2)(3)
#define TAIL(x) EAT x
#define EAT(...)
This provides some better detection of parenthesis and emptiness. And it provides a HEAD and TAIL macro which works slightly different than BOOST_PP_SEQ_HEAD. (Boost.Preprocessor can't handle sequences that have vardiac parameters). Now heres how we can define a TO_SEQ macro which uses the while construct:
#define TO_SEQ(x) TO_SEQ_WHILE_M \
( \
BOOST_PP_WHILE(TO_SEQ_WHILE_P, TO_SEQ_WHILE_O, (,x)) \
)
#define TO_SEQ_WHILE_P(r, state) TO_SEQ_P state
#define TO_SEQ_WHILE_O(r, state) TO_SEQ_O state
#define TO_SEQ_WHILE_M(state) TO_SEQ_M state
#define TO_SEQ_P(prev, tail) BOOST_PP_NOT(IS_EMPTY(tail))
#define TO_SEQ_O(prev, tail) \
BOOST_PP_IF(IS_PAREN(tail), \
TO_SEQ_PAREN, \
TO_SEQ_KEYWORD \
)(prev, tail)
#define TO_SEQ_PAREN(prev, tail) \
(prev (HEAD(tail)), TAIL(tail))
#define TO_SEQ_KEYWORD(prev, tail) \
TO_SEQ_REPLACE(prev, KEYWORD(tail))
#define TO_SEQ_REPLACE(prev, tail) \
(prev HEAD(tail), TAIL(tail))
#define TO_SEQ_M(prev, tail) prev
Now when you call TO_SEQ(take(x*x) with(x, container)) you should get a sequence (take)((x*x))(with)((x, container)).
Now, this sequence is much easier to work with(because of the Boost.Preprocessor library). You can now reverse it, transform it, filter it, fold over it, etc. This is extremely powerful, and is much more flexible than having them defined as macros. For example, in the Linq library the query from(x, numbers) where(x > 2) select(x * x) gets transformed into these macros:
LINQ_WHERE(x, numbers)(x > 2) LINQ_SELECT(x, numbers)(x * x)
Which these macros, it will then generate the lambda for list comprehension, but they have much more to work with when it generates the lambda. The same can be done in your library too, take(x*x) with(x, container) could be transformed into something like this:
FREEZE_TAKE(x, container, x*x)
Plus, you aren't defining macros like take which invade the global space.
Note: These macros here require a C99 preprocessor and thus won't work in MSVC.(There are workarounds though)