5

So, I am trying to replace the following code (C++11):

struct test { const char *n; int i; std::function<int(void)> read; std::function<void(int)> write; }; #define define_test(n, i, bodyRead, bodyWrite) \ { n, i, []() { bodyRead; }, [](int v) { bodyWrite; } } std::initializer_list<test> tests = { define_test("test1", 1, return 1, v = 2), ... }; 

with a C++03 compatible code that gives the same effect:

struct test { test(const char *_n, int _i, boost::function<int(void)> _read, boost::function<void(int)> _write) { n = _n; i = _i; read = _read; write = _write; } const char *n; int i; boost::function<int(void)> read; boost::function<void(int)> write; }; #define define_test(n, i, bodyRead, bodyWrite) \ ( n, i, []() { bodyRead; }, [](int v) { bodyWrite; } ) std::vector<test> tests; static void init_tests(void) { tests.push_back(define_test("test1", 1, return 1, v = 2)); } 

With no doubt, The Visual C++ Studio 2008 Express SP1 compiler rejects the lambda expressions, using boost wouldn't help it either, except was bind() and the lambda boost got, which I am not exactly sure how I would do it with this.

To elaborate more on this, I want to also be able to use like so:

using namespace boost::assign; static std::vector<test> tests; static void init_tests(void) { push_back(tests) define_test(...) ...; } 

that means structs with static functions won't be of much help either e.g.:

#define define_test(n, i, bodyRead, bodyWrite) \ struct { static void fn##n(void) { bodyRead; } \ static void fnw##n(int v) { bodyWrite; } \ }; \ ( n, i, boost::bind(&fn##n), boost::bind(&fnw##n, boost::placeholders::_1) ) 

That's because I am writing a ton of this and C++11 was so easy.

2
  • I fear, you are looking for convenience disturbing maintenance of code. (Passing a non trivial function as a macro parameter) Commented Feb 5, 2015 at 20:19
  • @DieterLücking Well, I ended up redesigning this whole thing :( gotta love C++ Commented Feb 6, 2015 at 0:52

1 Answer 1

4

You can cobble something together with Boost Phoenix, for example.

s_tests.push_back(test ( "test1", 1, phx::val(1), phx::ref(v) = arg1*1 )); s_tests.push_back(test ( "test2", 2, phx::val(2), phx::ref(v) = arg1*2 )); 

It will not achieve the natural C++ syntax, but at least it will be pretty full featured (it supports exceptions, while_, for_, switch_, locals, bind() etc.):

Live On Coliru

#include <boost/function.hpp> struct test { const char *n; int i; boost::function<int(void)> read; boost::function<void(int)> write; test(char const* n, int i, boost::function<int(void)> read, boost::function<void(int)> write) : n(n), i(i), read(read), write(write) {} }; #include <boost/phoenix.hpp> #include <vector> using namespace boost::phoenix::arg_names; namespace phx = boost::phoenix; namespace mocks { static int v; typedef std::vector<test> test_t; test_t const& tests() { static test_t s_tests; if (s_tests.empty()) { s_tests.push_back(test ( "test1", 1, phx::val(1), phx::ref(v) = arg1*1 )); s_tests.push_back(test ( "test2", 2, phx::val(2), phx::ref(v) = arg1*2 )); } return s_tests; } } #include <iostream> int main() { for (mocks::test_t::const_iterator it = mocks::tests().begin(); it != mocks::tests().end(); ++it) { test const& test = *it; std::cout << "'" << test.n << "'\t" << test.i << ", " << test.read() << ", "; test.write(42); std::cout << "mock v: " << mocks::v << "\n"; } } 

Prints

'test1' 1, 1, mock v: 42 'test2' 2, 2, mock v: 84 
Sign up to request clarification or add additional context in comments.

3 Comments

Made the sample truly live and c++03 proof. (Of course, there were many other details c++11 specific.)
Sorry if my comment was a little vague. Let's say I want to save some typing, by e.g. #define define_test(n, i, bodyRead, bodyWrite) (n, i, boost::phoenix::val(bodyRead), boost::phoenix::ref(v) = boost::phoenix::arg_names::arg1; if_ (v) [ bodyWrite; ] } or maybe just [ bodyWrite; ]
I'm not sure what typing you're trying to save. I don't think you be able to include "natural C++ statements" directly in your dreamed macro (this is kind of the selling point of of lambdas). However, in my opinion, the Boost Phoenix does a pretty decent job coming close. I'd suggest to per-use the linked pages, or to rethink your requirements :)