Is there a way to generate this kind of macro with some other macro?
E.g. a struct with 3 members or something...
#define CONST_STRUCT2(name, name1, type1, name2, type2) \
struct name \
{ \
name(const type1& p##name1, const type2& p##name2) \
: name1(p##name1), name2(p##name2) {} \
const type1 name1; const type2 name2; \
};
Yes, you can do it with Boost.Preprocessor.
#define CONST_STRUCT(name, members) \
struct name \
{ \
name(GENERATE_CTOR_PARAMS(members)) \
: GENERATE_CTOR_INITIALISERS(members) {} \
GENERATE_MEMBERS(members) \
}
#define PARAM_TYPE(param) \
BOOST_PP_TUPLE_ELEM(2, 0, param)
#define PARAM_NAME(param) \
BOOST_PP_TUPLE_ELEM(2, 1, param)
#define GENERATE_CTOR_PARAMS(members) \
BOOST_PP_ENUM(BOOST_PP_SEQ_SIZE(members), GENERATE_CTOR_PARAM, members)
#define GENERATE_CTOR_PARAM(z, idx, members) \
const PARAM_TYPE(BOOST_PP_SEQ_ELEM(idx, members)) & PARAM_NAME(BOOST_PP_SEQ_ELEM(idx, members))
#define GENERATE_CTOR_INITIALISERS(members) \
BOOST_PP_ENUM(BOOST_PP_SEQ_SIZE(members), GENERATE_CTOR_INITIALISER, members)
#define GENERATE_CTOR_INITIALISER(z, idx, members) \
PARAM_NAME(BOOST_PP_SEQ_ELEM(idx, members)) (PARAM_NAME(BOOST_PP_SEQ_ELEM(idx, members)))
#define GENERATE_MEMBERS(members) \
BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(members), GENERATE_MEMBER, members)
#define GENERATE_MEMBER(z, idx, members) \
const PARAM_TYPE(BOOST_PP_SEQ_ELEM(idx, members)) PARAM_NAME(BOOST_PP_SEQ_ELEM(idx, members));
Example of use:
CONST_STRUCT(Three, ((type1, name1))((type2, name2))((type3, name3)));
Necessary header files omitted for clarity. Also, in a real application, choose better scoped names (such as CONST_STRUCT_GENERATE_...).
Related
I was reading an article about mock and fake object from Unity folks and then I saw this code:
FAKE_FUNCTION(GetScriptingManager, ScriptingManager&());
FAKE_FUNCTION macro is defined as:
#define FAKE_FUNCTION(functionName, signature) \
FAKE_FUNCTION_IMPL(functionName, functionName, signature)
And FAKE_FUNCTION_IMPL is defined as:
#define FAKE_FUNCTION_IMPL(localName, functionName, signature) \
struct __Fake ## localName : public ::testing::FakeFunction<signature> \
{ \
__Fake ## localName() \
: ::testing::FakeFunction<signature>(#functionName) {} \
}; \
__Fake ## localName localName
What's the meaning of ScriptingManager&()? I understood that's the argument of a template but I can't recall seeing such construct in C++.
Let's say I have some unspecified type called variant, as well as two functions allowing to convert to/from this type, with the following signature:
struct converter
{
template<typename T>
static variant to(const T&);
template<typename T>
static T from(const variant&);
};
Now, what I'd like to do is create wrappers for arbitrary C++ functions as in the following example:
SomeObject f_unwrapped(const std::string& s, int* x)
{
//... do something with the inputs...
return SomeObject();
}
extern "C" variant f(variant s, variant x)
{
return converter::to<SomeObject>(f_unwrapped(converter::from<std::string>(s), converter::from<int*>(x)));
}
Ideally I'd want the wrapper to be a one-line declaration or macro that would take only the f_unwrapped function and the name f as inputs.
I've tried to wrap the function into a function object, then do the bureaucratic work using variadic templates. While this does work, I don't know how to make the resulting function extern "C".
What is the most idiomatic way of achieving this goal?
If we use the EVAL, helper, Conditional, and map macros from the first two code blocks here.
The map will need to be made more general for our needs.
#define MM1() MM_CALL1
#define MM_NEXT1(Macro,a,...) \
IS_DONE(a)( \
EAT \
, \
OBSTRUCT(COMMA)() OBSTRUCT(MM1)() \
) \
(Macro,a,__VA_ARGS__)
#define MM_CALL1(Macro,a,...) \
Macro(a) \
MM_NEXT1(Macro,__VA_ARGS__)
#define MacroMap1(Macro,...) MM_CALL1(Macro,__VA_ARGS__,DONE)
#define MM2() MM_CALL2
#define MM_NEXT2(Macro,a,...) \
IS_DONE(a)( \
EAT \
, \
OBSTRUCT(COMMA)() OBSTRUCT(MM2)() \
) \
(Macro,a,__VA_ARGS__)
#define MM_CALL2(Macro,a,b,...) \
Macro(a,b) \
MM_NEXT2(Macro,__VA_ARGS__)
#define MacroMap2(Macro,...) MM_CALL2(Macro,__VA_ARGS__,DONE)
We will also want the WithTypes and WithoutTypes from here.
We can define AMACRO to do the job you wanted.
#define AsVariant(param) variant param
#define ConvertFrom(type,param) converter::from<type>(param)
#define HEADDER(type,func,params) type func ##_unwrapped (WithTypes params)
#define WRAPPER(type,func,params) \
extern "C" variant func (OBSTRUCT(MacroMap1)(AsVariant,WithoutTypes params)) \
{ \
return converter::to< type >(func ## _unwrapped( \
MacroMap2(ConvertFrom,IDENT params) \
)); \
}
#define AMACRO(type,func,params) \
EVAL( \
HEADDER(type,func,params); \
WRAPPER(type,func,params) \
HEADDER(type,func,params) \
)
Which will turn this:
AMACRO(SomeObject,f,(const std::string&, s, int*, x))
{
// ... do something with the inputs ...
return SomeObject();
}
Into this (after formatting):
SomeObject f_unwrapped (const std::string& s , int* x );
extern "C" variant f (variant s , variant x )
{
return converter::to<SomeObject>(f_unwrapped(converter::from<const std::string&>(s),converter::from<int*>(x)));
}
SomeObject f_unwrapped (const std::string& s , int* x )
{
return SomeObject();
}
NOTE:
If the const needs removing from the parameter, a conditional, similar to the ISDONE, can be made and added to the ConvertFrom macro.
I am trying to find Poco ByteOrder::ToNetwork() in the Poco source code and all I can find, after searching the entire source, is this:
static Int16 toNetwork(Int16 value);
static UInt16 toNetwork (UInt16 value);
static Int32 toNetwork(Int32 value);
static UInt32 toNetwork (UInt32 value);
#if defined(POCO_HAVE_INT64)
static Int64 toNetwork(Int64 value);
static UInt64 toNetwork (UInt64 value);
#endif
in ByteOrder.h
Where is the actual implementation? Can't find it on github either:
https://github.com/pocoproject/poco/search?utf8=%E2%9C%93&q=tonetwork
Poco's endiness conversions are defined by the macros POCO_IMPLEMENT_BYTEORDER_BIG and POCO_IMPLEMENT_BYTEORDER_LIT in ByteOrder.h. On big endian systems those macros expand to POCO_IMPLEMENT_BYTEORDER_NOOP and POCO_IMPLEMENT_BYTEORDER_FLIP respectively and the opposite on little endian systems.
//
// some macro trickery to automate the method implementation
//
#define POCO_IMPLEMENT_BYTEORDER_NOOP_(op, type) \
inline type ByteOrder::op(type value) \
{ \
return value; \
}
#define POCO_IMPLEMENT_BYTEORDER_FLIP_(op, type) \
inline type ByteOrder::op(type value) \
{ \
return flipBytes(value); \
}
#if defined(POCO_HAVE_INT64)
#define POCO_IMPLEMENT_BYTEORDER_NOOP(op) \
POCO_IMPLEMENT_BYTEORDER_NOOP_(op, Int16) \
POCO_IMPLEMENT_BYTEORDER_NOOP_(op, UInt16) \
POCO_IMPLEMENT_BYTEORDER_NOOP_(op, Int32) \
POCO_IMPLEMENT_BYTEORDER_NOOP_(op, UInt32) \
POCO_IMPLEMENT_BYTEORDER_NOOP_(op, Int64) \
POCO_IMPLEMENT_BYTEORDER_NOOP_(op, UInt64)
#define POCO_IMPLEMENT_BYTEORDER_FLIP(op) \
POCO_IMPLEMENT_BYTEORDER_FLIP_(op, Int16) \
POCO_IMPLEMENT_BYTEORDER_FLIP_(op, UInt16) \
POCO_IMPLEMENT_BYTEORDER_FLIP_(op, Int32) \
POCO_IMPLEMENT_BYTEORDER_FLIP_(op, UInt32) \
POCO_IMPLEMENT_BYTEORDER_FLIP_(op, Int64) \
POCO_IMPLEMENT_BYTEORDER_FLIP_(op, UInt64)
#else
#define POCO_IMPLEMENT_BYTEORDER_NOOP(op) \
POCO_IMPLEMENT_BYTEORDER_NOOP_(op, Int16) \
POCO_IMPLEMENT_BYTEORDER_NOOP_(op, UInt16) \
POCO_IMPLEMENT_BYTEORDER_NOOP_(op, Int32) \
POCO_IMPLEMENT_BYTEORDER_NOOP_(op, UInt32)
#define POCO_IMPLEMENT_BYTEORDER_FLIP(op) \
POCO_IMPLEMENT_BYTEORDER_FLIP_(op, Int16) \
POCO_IMPLEMENT_BYTEORDER_FLIP_(op, UInt16) \
POCO_IMPLEMENT_BYTEORDER_FLIP_(op, Int32) \
POCO_IMPLEMENT_BYTEORDER_FLIP_(op, UInt32)
#endif
#if defined(POCO_ARCH_BIG_ENDIAN)
#define POCO_IMPLEMENT_BYTEORDER_BIG POCO_IMPLEMENT_BYTEORDER_NOOP
#define POCO_IMPLEMENT_BYTEORDER_LIT POCO_IMPLEMENT_BYTEORDER_FLIP
#else
#define POCO_IMPLEMENT_BYTEORDER_BIG POCO_IMPLEMENT_BYTEORDER_FLIP
#define POCO_IMPLEMENT_BYTEORDER_LIT POCO_IMPLEMENT_BYTEORDER_NOOP
#endif
POCO_IMPLEMENT_BYTEORDER_BIG(toBigEndian)
POCO_IMPLEMENT_BYTEORDER_BIG(fromBigEndian)
POCO_IMPLEMENT_BYTEORDER_BIG(toNetwork)
POCO_IMPLEMENT_BYTEORDER_BIG(fromNetwork)
POCO_IMPLEMENT_BYTEORDER_LIT(toLittleEndian)
POCO_IMPLEMENT_BYTEORDER_LIT(fromLittleEndian)
I have a following struct:
struct Data
{
std::string firstMember;
std::string secondMember;
std::string thirdMember;
};
I want to select one of the members by string name in constexpr manner, like
Data instance;
auto& member = getMember(instance, "firstMember");
getMember is constexpr function/struct/macros/whatever in question and expression should be (I want it to be) optimized into simple auto& member = instance.firstMember;. My desire here is to be able to call getMember from another constexpr function, which in turn are computing name of particular member --> some kind of compile time reflection.
I know, there is no reflection in C++, therefore it's OK to register somehow (partially specialize? use some macros magic?) names of members of struct in question, like:
REGISTER_MEMBER(Data, "firstMember", firstMember);
All I want is to have that compile time optimization and do nothing in runtime. Is that possible in C++11 and how?
As noted in the comments, first take a look at BOOST_FUSION_ADAPT_STRUCT (and friends):
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
struct Data
{
std::string firstMember;
std::string secondMember;
std::string thirdMember;
};
BOOST_FUSION_ADAPT_STRUCT(
Data,
(std::string, firstMember)
(std::string, secondMember)
(std::string, thirdMember)
)
This turns your Data structure into a sequence usable by Fusion:
#include <boost/fusion/include/at_c.hpp>
int main()
{
Data d = { "firstData", "secondData", "thirdData" };
std::cout << boost::fusion::at_c<0>(d) << std::endl;
}
This prints "firstData". Change the index to refer to the members in order.
There, now we can refer to members at compile-time using a number. But you wanted a name. Also noted in the comments, processing strings is a runtime feature...almost. C++11 gives us constexpr.
It's a bit tricky, but ultimately it looks like this:
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/seq.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <stdexcept>
// and repeat for BOOST_FUSION_ADAPT_TPL_STRUCT, etc...
#define REFLECT_STRUCT(NAME, ATTRIBUTES) \
REFLECT_STRUCT_DETAIL(NAME, \
ATTRIBUTES, \
BOOST_PP_SEQ_POP_FRONT( \
BOOST_PP_CAT( \
/* warning: uses fusion implementation details: */ \
BOOST_FUSION_ADAPT_STRUCT_FILLER_0(0,0)ATTRIBUTES, \
_END))) \
#define REFLECT_STRUCT_DETAIL(NAME, ATTRIBUTES, WRAPPEDATTRIBUTES) \
BOOST_FUSION_ADAPT_STRUCT(NAME, ATTRIBUTES) \
\
namespace detail \
{ \
namespace BOOST_PP_CAT(reflect_, NAME) \
{ \
template <int N> \
struct member_name; \
\
BOOST_PP_SEQ_FOR_EACH_I(REFLECT_STRUCT_DETAIL_MEMBER_NAME, \
BOOST_PP_EMPTY, \
WRAPPEDATTRIBUTES) \
\
template <int N> \
constexpr bool member_match_index(const std::size_t index, \
const char* const str, \
const std::size_t len) \
{ \
return index == len || \
(member_name<N>::value()[index] == str[index] \
&& member_match_index<N>(index + 1, str, len)); \
} \
\
template <int N> \
constexpr bool member_match(const char* const str, \
const std::size_t len) \
{ \
return len == member_name<N>::value_length \
&& member_match_index<N>(0, str, len); \
} \
\
constexpr int find_member(const char* const str, \
const std::size_t len) \
{ \
return BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(WRAPPEDATTRIBUTES), \
REFLECT_STRUCT_DETAIL_MEMBER_NAME_TEST, \
BOOST_PP_EMPTY) \
throw std::runtime_error("could not find " \
BOOST_PP_STRINGIZE(NAME) \
" member"); \
} \
} \
} \
\
constexpr int BOOST_PP_CAT(indexof_, NAME)(const char* const str, \
const std::size_t len) \
{ \
return detail::BOOST_PP_CAT(reflect_, NAME)::find_member(str, len); \
} \
\
template <std::size_t N> \
constexpr int BOOST_PP_CAT(indexof_, NAME)(const char (&str)[N]) \
{ \
return detail::BOOST_PP_CAT(reflect_, NAME)::find_member(&str[0], N); \
}
#define REFLECT_STRUCT_DETAIL_EXTRACT_NAME(pair) \
BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(1, pair))
#define REFLECT_STRUCT_DETAIL_MEMBER_NAME(r, data, n, elem) \
REFLECT_STRUCT_DETAIL_MEMBER_NAME_DETAIL(n, REFLECT_STRUCT_DETAIL_EXTRACT_NAME(elem))
#define REFLECT_STRUCT_DETAIL_MEMBER_NAME_DETAIL(n, name) \
template <> \
struct member_name<n> \
{ \
static constexpr std::size_t value_length = sizeof(name); \
typedef const char value_type[value_length]; \
\
static constexpr const value_type& value() \
{ \
return name; \
} \
};
#define REFLECT_STRUCT_DETAIL_MEMBER_NAME_TEST(z, n, text) \
member_match<n>(str, len) ? n :
It looks scary but its readable if you take the time to pick it apart.
We have to introduce our own macros to give constant-expression access to the member names; most of the ugly comes from processing Boost.Preprocessor lists. Although Fusion does record the names during adaptation as well (see boost::fusion::extension::struct_member_name), they are not marked as constexpr so aren't usable to us, unfortunately.
This gives:
#include <boost/fusion/include/at_c.hpp>
#include <iostream>
#include <string>
struct Data
{
std::string firstMember;
std::string secondMember;
std::string thirdMember;
};
REFLECT_STRUCT(
Data,
(std::string, firstMember)
(std::string, secondMember)
(std::string, thirdMember)
)
// your desired code:
// (note the use of at_c ensures this is evaluated at comple-time)
#define GETMEMBER(data, member) boost::fusion::at_c<indexof_Data(member)>(data)
int main()
{
Data d = { "firstData", "secondData", "thirdData" };
std::cout << boost::fusion::at_c<indexof_Data("firstMember")>(d) << std::endl;
std::cout << GETMEMBER(d, "secondMember") << std::endl;
std::cout << GETMEMBER(d, "thirdMember") << std::endl;
/* causes error: std::cout << GETMEMBER(d, "nonexistent_member") << std::endl; */
}
Which I think is close to what you were after.
But keep in mind this may not all be necessary: Boost.Fusion may already have what you need. It lives in the area between pure compile-time stuff (Boost.MPL) and regular run-time stuff; adapt your struct and you can already do things like iterate over it (boost::fusion::for_each).
Is it possible to mix up the BOOST_AUTO_TEST_CASE and BOOST_AUTO_TEST_CASE_TEMPLATE macros with the BOOST_PARAM_TEST_CASE in any way? I'm even interested in really messy ways of making this happen.
Having to build all of your test cases by hand seems really tedious. But the BOOST_PARAM_TEST_CASE mechanism is pretty darn useful, but only works if you have a test init function, which in turn requires you to have be using manual test case construction.
Is there any documentation on how to hook into the automated system yourself so you can provide your own tests that auto-register themselves?
I'm using boost 1.46 right now.
I wrote my own support for this since there really didn't seem to be any good support. This requires the C++11 decltype feature and the ::std::remove_const and ::std::remove_reference library methods to work.
The macro definitions are a modified versions of the BOOST_FIXTURE_TEST_CASE and BOOST_AUTO_TEST_CASE macros.
You use this by declaring your function thus:
BOOST_AUTO_PARAM_TEST_CASE(name, begin, end)
{
BOOST_CHECK_LT(param, 5); // The function will have an argument named 'param'.
}
Here is the header that defines the BOOST_AUTO_PARAM_TEST_CASE macro:
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/parameterized_test.hpp>
#include <type_traits>
#define BOOST_FIXTURE_PARAM_TEST_CASE( test_name, F, mbegin, mend ) \
struct test_name : public F { \
typedef ::std::remove_const< ::std::remove_reference< decltype(*(mbegin)) >::type>::type param_t; \
void test_method(const param_t &); \
}; \
\
void BOOST_AUTO_TC_INVOKER( test_name )(const test_name::param_t ¶m) \
{ \
test_name t; \
t.test_method(param); \
} \
\
BOOST_AUTO_TU_REGISTRAR( test_name )( \
boost::unit_test::make_test_case( \
&BOOST_AUTO_TC_INVOKER( test_name ), #test_name, \
(mbegin), (mend))); \
\
void test_name::test_method(const param_t ¶m) \
// *******
#define BOOST_AUTO_PARAM_TEST_CASE( test_name, mbegin, mend ) \
BOOST_FIXTURE_PARAM_TEST_CASE( test_name, \
BOOST_AUTO_TEST_CASE_FIXTURE, \
mbegin, mend)
The solution provided by #Omnifarious works works, but requires a C++11 compiler.
Adapting that solution for a C++03 compiler:
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/parameterized_test.hpp>
#define BOOST_FIXTURE_PARAM_TEST_CASE( test_name, F, P, mbegin, mend ) \
struct test_name : public F \
{ \
typedef P param_t; \
void test_method(const param_t &); \
}; \
\
void BOOST_AUTO_TC_INVOKER( test_name )(const test_name::param_t ¶m) \
{ \
test_name t; \
t.test_method(param); \
} \
\
BOOST_AUTO_TU_REGISTRAR( test_name )( \
boost::unit_test::make_test_case( \
&BOOST_AUTO_TC_INVOKER( test_name ), #test_name, \
(mbegin), (mend))); \
\
void test_name::test_method(const param_t ¶m) \
// *******
#define BOOST_AUTO_PARAM_TEST_CASE( test_name, param_type, mbegin, mend ) \
BOOST_FIXTURE_PARAM_TEST_CASE( test_name, \
BOOST_AUTO_TEST_CASE_FIXTURE, \
param_type, \
mbegin, mend)
This solution is slightly different is usage. Since there is no declspec in C++03, the type of the parameter object cannot be automatically deduced. We must pass it in as a parameter to BOOST_AUTO_PARAM_TEST_CASE:
class FooTestParam
{
public:
std::string mS;
FooTestParam (int n)
{
std::stringstream ss;
ss << n;
mS = ss.str();
}
};
FooTestParam fooParams [] =
{
FooTestParam (42),
FooTestParam (314)
};
BOOST_AUTO_PARAM_TEST_CASE (TestFoo, FooTestParam, fooParams, fooParams + 2)
{
const std::string testVal = param.mS;
}
BOOST_AUTO_TEST_CASE (TestAddressField)
{
const uint32_t raw = 0x0100007f; // 127.0.0.1
const uint8_t expected[4] = {127, 0, 0, 1};
const Mdi::AddressField& field = *reinterpret_cast <const Mdi::AddressField*> (&raw);
for (size_t i = 0; i < 4; ++i)
BOOST_CHECK_EQUAL (field[i], expected[i]);
}
Starting with Boost version 1.59, this is being handled by data-driven test cases:
#define BOOST_TEST_MODULE MainTest
#include <boost/test/included/unit_test.hpp>
#include <boost/test/data/test_case.hpp>
#include <boost/array.hpp>
static const boost::array< int, 4 > DATA{ 1, 3, 4, 5 };
BOOST_DATA_TEST_CASE( Foo, DATA )
{
BOOST_TEST( sample % 2 );
}
This functionality requires C++11 support from compiler and library, and does not work inside a BOOST_AUTO_TEST_SUITE.
If you have to support both old and new versions of Boost in your source, and / or pre-C++11 compilers, check out And-y's answer.
You can easily mix manual and automated test unit registration. Implement your own init function (like in example 20 on this page) and inside init function you can perform registration for parameterized test cases. Boost.Test will merge them both into single test tree.
Since Boost 1.59 internal details of realization was changed and Omnifarious's solution doesn't compile.
Reason ot that is changing signature of boost::unit_test::make_test_case function: now it take 2 additional args: __FILE__, __LINE__
Fixed solution:
#if BOOST_VERSION > 105800
#define MY_BOOST_TEST_ADD_ARGS __FILE__, __LINE__,
#define MY_BOOST_TEST_DEFAULT_DEC_COLLECTOR ,boost::unit_test::decorator::collector::instance()
#else
#define MY_BOOST_TEST_ADD_ARGS
#define MY_BOOST_TEST_DEFAULT_DEC_COLLECTOR
#endif
#define BOOST_FIXTURE_PARAM_TEST_CASE( test_name, F, mbegin, mend ) \
struct test_name : public F { \
typedef ::std::remove_const< ::std::remove_reference< decltype(*(mbegin)) >::type>::type param_t; \
void test_method(const param_t &); \
}; \
\
void BOOST_AUTO_TC_INVOKER( test_name )(const test_name::param_t ¶m) \
{ \
test_name t; \
t.test_method(param); \
} \
\
BOOST_AUTO_TU_REGISTRAR( test_name )( \
boost::unit_test::make_test_case( \
&BOOST_AUTO_TC_INVOKER( test_name ), #test_name, \
MY_BOOST_TEST_ADD_ARGS \
(mbegin), (mend)) \
MY_BOOST_TEST_DEFAULT_DEC_COLLECTOR); \
\
void test_name::test_method(const param_t ¶m) \
#define BOOST_AUTO_PARAM_TEST_CASE( test_name, mbegin, mend ) \
BOOST_FIXTURE_PARAM_TEST_CASE( test_name, \
BOOST_AUTO_TEST_CASE_FIXTURE, \
mbegin, mend)
I took Omnifarious' header file and modified it such that the parameter is passed to the constructor of the test fixture rather than to the test method. This requires the test fixture's constructor declaration to take a single argument with the parameter's type. I found this to be super handy--much thanks for the initial question and answer!
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/parameterized_test.hpp>
#include <type_traits>
#define BOOST_FIXTURE_PARAM_TEST_CASE( test_name, F, mbegin, mend ) \
struct test_name : public F { \
typedef ::std::remove_const< ::std::remove_reference< decltype(*(mbegin)) >::type>::type param_t; \
test_name(const param_t ¶m) : F(param) {} \
void test_method(void); \
}; \
\
void BOOST_AUTO_TC_INVOKER( test_name )(const test_name::param_t ¶m)\
{ \
test_name t(param); \
t.test_method(); \
} \
\
BOOST_AUTO_TU_REGISTRAR( test_name )( \
boost::unit_test::make_test_case( \
&BOOST_AUTO_TC_INVOKER( test_name ), #test_name, \
(mbegin), (mend))); \
\
void test_name::test_method(void) \
// *******
#define BOOST_AUTO_PARAM_TEST_CASE( test_name, mbegin, mend ) \
BOOST_FIXTURE_PARAM_TEST_CASE( test_name, \
BOOST_AUTO_TEST_CASE_FIXTURE, \
mbegin, mend)