Re: A silly macro technique
Noah Roberts wrote:
In article <hm0d4f$a0k$1@news.eternal-september.org>, alfps@start.no
says...
Replace "debugger api" with "whatever" in this
<code>
#define USE_DEBUGGER_API // Or not
extern void useDebuggerApi();
#define CALL_IF_EXPANDED( doIt, f ) \
struct S_##f { \
struct Size2 { char x[2]; }; \
char foo( ... ) { return 0; } \
Size2 foo##doIt( int ) { return Size2(); } \
}; \
(sizeof( S_##f().foo(0) ) > 1 ? f() : (void)0)
#define CALL_IF( doIt, f ) CALL_IF_EXPANDED( doIt, f )
int main()
{
CALL_IF( USE_DEBUGGER_API, useDebuggerApi );
}
</code>
And why is it silly?
Well, if only routine is called in any particular build, then there could just
be a macro FUNCNAME, say, defined as the name of the routine to call.
But hey!
Actually I found a use for it.
Neat trick but I'd be interested to see anything that couldn't be done
in an easier way.
Similar idea, different approach. I wanted to be able to pass things to
the function in question too if it got called. Doing anything sane with
a return value is impossible of course given that one may/may not even
call it in the end.
Mostly just an excuse to try the variadic template arguments out really.
I wanted the function pointers to be template arguments themselves, but
couldn't see a way to make that work and keep the type deduction going.
Totally pointless learning exercise for me, probably wouldn't ever
deploy this in production :)
Alan
#include <cstdlib>
#include <ctime>
#include <iostream>
template <int test>
class CallIfTrue {
template <typename Ret, typename... Args>
struct dispatcher {
typedef Ret (*F_ptr)(Args...);
const F_ptr f;
dispatcher(const F_ptr& f) : f(f) {}
Ret operator()(const Args&... args) const {
return f(args...);
}
};
public:
// Figure out how to use the dispatcher if we need args
template<typename T, typename... Args>
static dispatcher<T,Args...> dispatch(T(*F)(Args...)) {
return dispatcher<T,Args...>(F);
}
// Simple if no function args
template<typename T>
static T dispatch( T(F)()) {
return F();
}
};
template<>
class CallIfTrue<0> {
// Lets this work for both param and non-param cases
struct eater {
void operator()(...) const {
}
};
public:
// Don't care about anything if we don't call it
static eater dispatch(...) {
return eater();
}
};
#define CALL_IF_TRUE(x,y) CallIfTrue<(x)>::dispatch(y)
void foo(const int& a) { std::cout << "Foo(" << a << ")" << std::endl; }
void bar() { std::cout << "Bar()" << std::endl; }
int main() {
std::cout << "Should get called:" << std::endl;
CallIfTrue<1>::dispatch(foo)(1);
std::cout << "Shouldn't get called:" << std::endl;
CALL_IF_TRUE(0,foo)(1);
std::cout << "Should get called:" << std::endl;
CallIfTrue<1>::dispatch(bar);
std::cout << "Shouldn't get called:" << std::endl;
CALL_IF_TRUE(0,bar);
std::cout << "Should get called:" << std::endl;
CALL_IF_TRUE(1,foo)(100);
// This will fail to compile if we tried to use the retun value when
// it wasn't true
std::cout << "Time is: " << CALL_IF_TRUE(-1,time)(NULL) << std::endl;
return 0;
}