Dynamic dispatch based on Enum value - c++

Lets say I'm trying to write multiple handlers for multiple message types.
enum MESSAGE_TYPE { TYPE_ZERO, TYPE_ONE, TYPE_TWO, TYPE_THREE, TYPE_FOUR };
One solution might be
void handler_for_type_one(...){ ... }
void handler_for_type_two(...){ ... }
...
switch(message_type){
case TYPE_ONE: handler_for_type_one(); break;
case TYPE_TWO: handler_for_type_two(); break;
...
And yeah, that would work fine. But now I want to add logging that wraps each of the handlers. Let's say a simple printf at the beginning / end of the handler function (before and after is fine too).
So maybe I do this:
template<MESSAGE_TYPE>
void handler() {
std::printf("[default]");
}
template<> void handler<TYPE_ONE>() {
std::printf("[one]");
}
template<> void handler<TYPE_TWO>() {
std::printf("[two]");
}
template<> void handler<TYPE_THREE>() {
std::printf("[three]");
}
int main()
{
std::printf("== COMPILE-TIME DISPATCH ==\n");
handler<TYPE_ZERO>();
handler<TYPE_ONE>();
handler<TYPE_TWO>();
handler<TYPE_THREE>();
handler<TYPE_FOUR>();
}
And it works how I'd expect:
== COMPILE-TIME DISPATCH ==
[default][one][two][three][default]
When the message-type is known at compile time, this works great. I don't even need that ugly switch. But outside of testing I won't know the message type and even if I did, wrap_handler (for the logging) "erases" that, requiring me to use the switch "map".
void wrap_handler(MESSAGE_TYPE mt) {
std::printf("(before) ");
switch (mt) {
case TYPE_ZERO: handler<TYPE_ZERO>(); break;
case TYPE_ONE: handler<TYPE_ONE>(); break;
case TYPE_TWO: handler<TYPE_TWO>(); break;
case TYPE_THREE: handler<TYPE_THREE>(); break;
//case TYPE_FOUR: handler<TYPE_FOUR>(); break; // Showing "undefined" path
default: std::printf("(undefined)");
}
std::printf(" (after)\n");
}
int main()
{
std::printf("== RUNTIME DISPATCH ==\n");
wrap_handler(TYPE_ZERO);
wrap_handler(TYPE_ONE);
wrap_handler(TYPE_TWO);
wrap_handler(TYPE_THREE);
wrap_handler(TYPE_FOUR);
}
== RUNTIME DISPATCH ==
(before) [default] (after)
(before) [one] (after)
(before) [two] (after)
(before) [three] (after)
(before) (undefined) (after)
My "goals" for the solution are:
Have the enum value as close to the handler definition as possible -- template specialization like I show above seems to be about the best I can do in this area, but I have no idea.
When adding a message-type/handler, I'd prefer to keep the changes as local/tight as possible. (Basically, I'm looking for any way to get rid of that switch).
If I do need a switch or map, etc., since it'd be far away from the new handler, I'd like a way at compile time to tell whether there's a message type (enum value) without a corresponding switch case. (Maybe make the switch a map/array? Not sure if you can get the size of an initialized map at compile time.)
Minimize boilerplate
The other solution that seems obvious is a virtual method that's overridden in different subclasses, one for each message type, but it doesn't seem like there's a way to "bind" a message type (enum value) to a specific implementation as cleanly as the template specialization above.
Just to round it out, this could be done perfectly with (other languages) decorators:
#handles(MESSAGE_TYPE.TYPE_ZERO)
def handler(...):
...
Any ideas?

One way I'd get rid of the manual switch statements is to use template recursion, as follows. First, we create an integer sequence of your enum class, like so:
enum MESSAGE_TYPE { TYPE_ZERO, TYPE_ONE, TYPE_TWO, TYPE_THREE, TYPE_FOUR };
using message_types = std::integer_sequence<MESSAGE_TYPE, TYPE_ZERO, TYPE_ONE, TYPE_TWO, TYPE_THREE, TYPE_FOUR>;
Second, let's change slightly the handler and make it a class with a static function:
template <MESSAGE_TYPE M>
struct Handler
{
// replace with this whatever your handler needs to do
static void handle(){std::cout << (int)M << std::endl;}
};
// specialise as required
template <>
struct Handler<MESSAGE_TYPE::TYPE_FOUR>
{
static void handle(){std::cout << "This is my last message type" << std::endl;}
};
Now, with these we can easily use template recursion to create a generic switch map:
template <class Sequence>
struct ct_map;
// specialisation to end recusion
template <class T, T Head>
struct ct_map<std::integer_sequence<T, Head>>
{
template <template <T> class F>
static void call(T t)
{
return F<Head>::handle();
}
};
// recursion
template <class T, T Head, T... Tail>
struct ct_map<std::integer_sequence<T, Head, Tail...>>
{
template <template <T> class F>
static void call(T t)
{
if(t == Head) return F<Head>::handle();
else return ct_map<std::integer_sequence<T, Tail...>>::template call<F>(t);
}
};
And use as follows:
int main()
{
ct_map<message_types>::call<Handler>(MESSAGE_TYPE::TYPE_ZERO);
ct_map<message_types>::call<Handler>(MESSAGE_TYPE::TYPE_THREE);
ct_map<message_types>::call<Handler>(MESSAGE_TYPE::TYPE_FOUR);
}
If now, you want to create your wraphandler, you can do this:
template <MESSAGE_TYPE M>
struct WrapHandler
{
static void handle()
{
std::cout << "Before" << std::endl;
Handler<M>::handle();
std::cout << "After" << std::endl;
}
};
int main()
{
ct_map<message_types>::call<WrapHandler>(MESSAGE_TYPE::TYPE_THREE);
}
Live code here

The way I understand it, a function pointer may be what you need.
Going from your example, the code would be like this:
template<MESSAGE_TYPE>
void handler() {
std::printf("[default]");
}
template<> void handler<TYPE_ONE>() {
std::printf("[one]");
}
template<> void handler<TYPE_TWO>() {
std::printf("[two]");
}
template<> void handler<TYPE_THREE>() {
std::printf("[three]");
}
void wrap_handler(void (*handler)()) {
std::printf("(before) ");
if (!handler)
std::printf("(undefined)");
else
handler();
std::printf(" (after)\n");
}
int main()
{
std::printf("== COMPILE-TIME DISPATCH ==\n");
handler<TYPE_ZERO>();
handler<TYPE_ONE>();
handler<TYPE_TWO>();
handler<TYPE_THREE>();
handler<TYPE_FOUR>();
std::printf("\n\n");
std::printf("== RUNTIME DISPATCH ==\n");
wrap_handler(TYPE_ZERO);
wrap_handler(TYPE_ONE);
wrap_handler(TYPE_TWO);
wrap_handler(TYPE_THREE);
wrap_handler(TYPE_FOUR);
}
The function pointer mirrors the prototype of the function (meaning all calls need to be compatible).
In order to pass an argument, the function would change to:
void wrap_handler(void (*handler)(ArgumentType), const ArgumentType &arg) {
std::printf("(before) ");
if (!handler)
std::printf("(undefined)");
else
handler(arg);
std::printf(" (after)\n");
}
A way around this would be to use std::function (C++11).
void wrap_handler(std::function<> handler) {
std::printf("(before) ");
if (!handler)
std::printf("(undefined)");
else
handler();
std::printf(" (after)\n");
}
Possible ways to call this include:
wrap_handler(&functionWithoutArguments);
wrap_handler(std::bind(functionWithArgument, someArgument);
wrap_handler([=](){ LambdaCode; });
etc.

This is a common problem for all applications receiving messages or events.
However, in C++ the switch or some kind of table of handlers is the best you can do. The reason is that the value of the enum only exists at run-time, therefore you cannot make that decision at compile time.
Other languages, like Python, can provide the solution you are looking for, because they are interpreted languages, so compile time and run-time are the same.
Boost asio is good example of how you can hide the switch, but my experience is that hiding it is not as good as you think at the first place.
When you need to debug your code or someone else has to find the handler which belongs to a certain event, or somehow, you have to check if the handler is registered you need to know, where the switch is, place a break point there, or log the incoming messages. This is much more difficult in systems like asio.

C++ requires the exact function signature to be figured out at compile time. This does include determining template parameters. You won't be able to get rid of some logic that determines the exact operation to execute, whether you're creating a map-like data structure for this or keep it a switch. If you're just worried about accidentally leaving out some enum constant in the switch or about the boilerplate code this may be the time to get the preprocessor involved.
#ifdef MESSAGE_TYPES
# error macro name conflict for MESSAGE_TYPES may result in errors
#endif
// x is a function-like macro that takes 1 parameter (2, if you want the constants to assigned a specific value)
#define MESSAGE_TYPES(x) \
x(TYPE_ZERO) \
x(TYPE_ONE) \
x(TYPE_TWO) \
x(TYPE_THREE) \
x(TYPE_FOUR)
#ifdef MESSAGE_TYPE_ENUM_CONSTANT
# error macro name conflict for MESSAGE_TYPE_ENUM_CONSTANT may result in errors
#endif
#define MESSAGE_TYPE_ENUM_CONSTANT(c) c,
enum MESSAGE_TYPE { MESSAGE_TYPES(MESSAGE_TYPE_ENUM_CONSTANT) };
#undef MESSAGE_TYPE_ENUM_CONSTANT
template<MESSAGE_TYPE>
void handler() {
std::printf("[default]");
}
template<> void handler<TYPE_ONE>() {
std::printf("[one]");
}
template<> void handler<TYPE_TWO>() {
std::printf("[two]");
}
template<> void handler<TYPE_THREE>() {
std::printf("[three]");
}
void wrap_handler(MESSAGE_TYPE mt) {
std::printf("(before) ");
#ifdef HANDLER_CALL_SWITCH_CASE
# error macro name conflict for HANDLER_CALL_SWITCH_CASE may result in errors
#endif
#define HANDLER_CALL_SWITCH_CASE(c) case c: handler<c>(); break;
switch (mt) {
MESSAGE_TYPES(HANDLER_CALL_SWITCH_CASE);
default:
std::printf("(undefined)");
break;
}
#undef HANDLER_CALL_SWITCH_CASE
std::printf(" (after)\n");
}
#undef MESSAGE_TYPES

Related

Meet two generic values in one function

I have two callbacks foo and bar, both taking a generic value each.
When both callbacks has been called I want these values to meet in single function. My test code is:
template <class FooType, class BarType>
void meet_point(FooType foo_value, BarType bar_value) {
// Success
}
struct test
{
template <class FooType>
void foo(FooType value) {
// TODO: save value or type somehow
}
template <class BarType>
void bar(BarType value) {
meet_point(/* FooType value from above */, value);
}
};
template <class F>
void sync_request(F&& f) {
f("foobar");
}
int main()
{
test t;
sync_request([&t](auto value) {
t.foo(value);
});
t.bar(42);
}
Is there any way to do it?
EDIT:
Note that code in main() is just an example of calling both callbacks. Actual calls happens from different places and both triggers do not know anything about each other.
Also at the time of instantiating test object no type is known ahead. Actually test struct is not even needed here. It could be standalone callbacks. It is there just for maybe possible storage of FooType value.
P.S.
I wish we had reflection, jit, Circle #type_id or templated virtual functions to extract the type in C++.
You need to know (or be able to exhaustively list the possibilities of) at least one of FooType or BarType.
Case 1: FooType is one of typename... FooTypes known when you instantiate a test.
template<typename... FooTypes>
struct test
{
using FooType = std::variant<FooTypes...>;
void foo(FooType value) {
foo_value = value;
}
template <class BarType>
void bar(BarType value) {
std::variant<BarType> bar_value = value;
std::visit(meet_point, foo_value, bar_value);
}
FooType foo_value;
};
Case 2: BarType is one of typename... BarTypes known when you instantiate a test.
template<typename... BarTypes>
struct test
{
using BarType = std::variant<BarTypes...>;
template <class FooType>
void foo(FooType value) {
std::variant<FooType> foo_value = value;
visit = [foo_value](BarType bar_value){ std::visit(meet_point, foo_value, bar_value); };
}
void bar(BarType value) {
visit(value)
}
function<void(std::variant<BarTypes...>)> visit;
};
Case 3: FooType is one of typename... FooTypes and BarType is one of typename... BarTypes, both known when you instantiate a test.
template<typename... FooTypes, typename... BarTypes>
struct test
{
using FooType = std::variant<FooTypes...>;
using BarType = std::variant<BarTypes...>;
void foo(FooType value) {
foo_value = value;
}
void bar(BarType bar_value) {
std::visit(meet_point, foo_value, bar_value);
}
std::variant<FooTypes...> foo_value;
};
When you write your code you do not know which types the user of your library will use. But when the user compiles his types has to be known. If you are fine with letting the user register his types you can do it like this:
#include <boost/algorithm/algorithm.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/hana.hpp>
#include <functional>
#include <iostream>
#include <type_traits>
// code you write
struct CallbackData
{
virtual ~CallbackData () = default;
};
// code your user writes for example in userTypes.h
struct TestFooType : CallbackData
{
int value = 42;
};
struct TestBarType : CallbackData
{
std::string value{ "bar type" };
};
struct AnotherTestFooType : CallbackData
{
int value = 42;
};
struct AnotherTestBarType : CallbackData
{
std::string value{ "bar type" };
};
static boost::hana::tuple<TestFooType, TestBarType, AnotherTestFooType, AnotherTestBarType> const sharedClasses{};
// code you write
struct test
{
void
bothAreReady ()
{
boost::hana::for_each (sharedClasses, [&] (auto x) {
if (std::shared_ptr<std::decay_t<decltype (x)>> firstValue = std::dynamic_pointer_cast<std::decay_t<decltype (x)>> (fooValue))
{
std::cout << "fooValue: " << firstValue->value << std::endl;
return;
}
});
boost::hana::for_each (sharedClasses, [&] (auto x) {
if (std::shared_ptr<std::decay_t<decltype (x)>> secondValue = std::dynamic_pointer_cast<std::decay_t<decltype (x)>> (barValue))
{
std::cout << "barValue: " << secondValue->value << std::endl;
return;
}
});
}
bool
isDone ()
{
return fooValue && barValue;
}
std::shared_ptr<CallbackData> fooValue{};
std::shared_ptr<CallbackData> barValue{};
};
// code your user writes
int
main ()
{
test t;
auto fooAction = [&t] () {
auto testFooType = TestFooType{};
// do something with test foo type
t.fooValue = std::shared_ptr<CallbackData>{ new std::decay_t<decltype (testFooType)>{ std::move (testFooType) } };
if (t.isDone ()) t.bothAreReady ();
};
auto barAction = [&t] () {
auto testBarType = TestBarType{};
// do something with testBarType
t.barValue = std::shared_ptr<CallbackData>{ new std::decay_t<decltype (testBarType)>{ std::move (testBarType) } };
if (t.isDone ()) t.bothAreReady ();
};
// run the lambdas on some other thread or so
fooAction ();
barAction ();
}
wandbox example
Alice live in Australia. Alice creates a nice class Alice, writes a source file that contains a call to test.foo(Alice()), builds a DLL, and ships it to you.
Bob lives in Bermuda. Bob creates a nice class Bob, writes a source file that contains a call to test.bar(Bob()), builds a DLL, and ships it to you.
Alice and Bob have never heard of each other and have never seen each other's code.
You have your program load the two DLLs and...
Where is meet_point<Alice, Bob>?
It cannot be in Alice's DLL, because Alice have never seen Bob's code.
It cannot be in Bob's DLL, because Bob have never seen Alice's code.
It cannot be in your program, because you have never seen the code of either of them! All you have is their DLL that call your code. They both obviously have your header that defines struct test, but this doesn't help at all.
So you need some tool that would go over Alice's and Bob's code, extract all types that are used in calls to foo and bar, and instantiate meet_point<a, b> with every possible pair (a, b) of such types. The problem is, there isn't such tool in any standard toolkit. You need to write one somehow.
The easiest way would be asking Alice and Bob to send you a list of their types used in calls to foo and bar. You can also go over their object code and extract these types from symbols or whatever. In any case you need them to send you header files with definitions of all their classes, so that you can compile each instantiation. Another option (not as crazy as it sounds) would be just-in-time compilation: make your class find the headers (you can know the names of the classes so that's doable), generate a source that instantiates meet_point with relevant arguments, run the compiler, build a DLL, load it, and call the function! Cache the DLL for later use. Of course it could happen that meet_point cannot be compiled with a particular combination of arguments, and you will only know it when this combination arrives.
Now "two developers that do not talk to each other send you DLLs" is an extreme model of the situation, but it doesn't actually create any new problem. It just makes it easier to see problems that are inherent in the situation.

C++ Call functions based on enum values

I have this code
class Foo {
private:
enum class Heuristic {
ONE,
TWO,
THREE
};
Heuristic h;
void select();
};
void Foo::select() {
if (h == Heuristic::ONE)
selectONE();
else if (h == Heuristic::TWO)
selectTWO();
else
selectTHREE();
}
void selectONE() {};
void selectTWO() {};
void selectTHREE() {};
Based on the value of heuristic I want to call a specific function in select(). I don't know the value of heuristic at compile time, as it depends on user input. To avoid the conditional check in select() I would like to use templates. How can I accomplish this?
As it depends on runtime values there is no way to get rid of some sort of runtime checks. Which are either done by you with if, switch, … or by a container like std::map, std::unordered_map
Due to that, your concern there should be readability and maintainability.
I would - like already suggested in a comment - use switch instead of if, but not because the compiler can optimize it better (IMHO the compiler will be able to generate the same code for both), but to allow the static analyzer to warn you about not used enums.
If the question is about performance concerns, then this should only be a problem if you call these functions at a high frequency. So if this is the case you could create a template-based entry point to your task, to which you pass the function as template argument based on the user selection:
template<auto SelectedHeuristic>
void Foo::task() {
for( /* … */ ) {
SelectedHeuristic();
}
}
void Foo::select() {
switch(h) {
case Heuristic::ONE:
Foo::task<selectONE>();
break;
case Heuristic::TWO:
Foo::task<selectTWO>();
break;
case Heuristic::THREE:
Foo::task<selectTHREE>();
break;
}
}
void selectONE() {};
void selectTWO() {};
void selectTHREE() {};
To avoid the conditional check in select() [...]
A simple way to avoid all conditional checks (hidden or otherwise) in select() could be to create an array of pointers to your functions. You then look the function up by using its current Heuristic value (which must start at 0 and not have any gaps). If the Heuristic value changes rarely, you can even move the lookup out of select() completely.
Example:
##include <iostream>
void selectONE() { std::cout << "one\n"; };
void selectTWO() { std::cout << "two\n"; };
void selectTHREE() { std::cout << "three\n"; };
using func_ptr_t = void(*)(); // the signature of your functions
class Foo {
public:
enum class Heuristic {
ONE,
TWO,
THREE
};
void set_heuristic(Heuristic); // a function to do the lookup
void select();
private:
Heuristic h;
func_ptr_t current_func; // a pointer to the selected function
};
void Foo::set_heuristic(Heuristic value) {
// a simple map from Heuristic value to function pointer
static const func_ptr_t funcmap[] = {
&selectONE,
&selectTWO,
&selectTHREE,
};
h = value; // perhaps not needed?
// look up the function pointer based on "h"
current_func = funcmap[static_cast<unsigned>(h)];
}
void Foo::select() {
// a pretty fast callsite:
current_func();
}
int main() {
Foo bar;
bar.set_heuristic(Foo::Heuristic::ONE);
bar.select(); // prints "one"
}
define a map<Heuristic, lambdas> where the lambdas are defined as
void and taking no parameters
void f()
then take the user input and get the value of that input key and trigger the lambda

C++ runtime type switching (avoiding switch)

I've been into C++ for some years but I have not found yet the solution to a problem I constantly have. Know how to solve it would be awesome.
What I have at the moment is:
// Client code:
switch(currentEnumValue)
{
case MyEnum::kValue01:
processData<MyEnum::kValue01>(data);
break;
case MyEnum::kValue02:
processData<MyEnum::kValue02>(data);
break;
default:
LOG("Invalid command");
break;
}
// Declarations
enum class MyEnum {kValue01, kValue02};
class MyClass
{
// code
template <MyEnum> void processData(char*); /* Implemented somewhere else */
}
template <> void MyClass::processData<MyEnum::kValue01>(char* data); /* Implemented somewhere else */
MyClass <> void MyClass::processData<MyEnum::kValue02>(char* data); /* Implemented somewhere else */
I would like to remove the switch because of many reasons. Instead of it I would need something like: processData<runtime-decltype(currentEnumValue)>(data);
I know about typeid and about not mixing compile time and runtime together... but despite this, I would like to find some solution anyway, preferably excluding macros.
This class makes a jump table for a given Enum up to a certain count size based off constructing some template and invoking it with the supplied args. It assumes the enum values start at 0, and go to Count-1.
template<class Enum, Enum Count, template<Enum>class Z>
struct magic_switch {
// return value of a call to magic_switch(Args...)
template<class...Args>
using R = std::result_of_t<Z<Enum(0)>(Args...)>;
// A function pointer for a jump table:
template<class...Args>
using F = R<Args...>(*)(Args&&...);
// Produces a single function pointer for index I and args Args...
template<size_t I, class...Args>
F<Args...> f() const {
using ret = R<Args...>;
return +[](Args&&...args)->ret{
using Invoke=Z<Enum(I)>;
return Invoke{}(std::forward<Args>(args)...);
};
}
// builds a jump table:
template<class...Args, size_t...Is>
std::array<F<Args...>,size_t(Count)>
table( std::index_sequence<Is...> ) const {
return {{
f<Is, Args...>()...
}};
}
template<class...Args>
R<Args...> operator()(Enum n, Args&&...args) {
// a static jump table for this case of Args...:
static auto jump=table<Args...>(std::make_index_sequence<size_t(Count)>{});
// Look up the nth entry in the jump table, and invoke it:
return jump[size_t(n)](std::forward<Args>(args)...);
}
};
then if you have an enum:
enum class abc_enum { a, b, c, count };
and a function object template:
template<abc_enum e>
struct stuff {
void operator()() const {
std::cout << (int)e << '\n';
}
};
you can dispatch:
magic_switch<abc_enum, abc_enum::count, stuff>{}(abc_enum::b);
in any case, within the template stuff, you get the enum value as a compile time constant. You call it with a run time constant.
Overhead should be similar to a switch statement, or a vtable call, depending on what the compiler does optimization wise.
live example.
Note that setting Enum to std::size_t is valid.
In C++11 you need make_index_sequence and index_sequence:
template<size_t...>
struct index_sequence {};
namespace details {
template<size_t Count, size_t...szs>
struct sequence_maker : sequence_maker<Count-1, Count-1, szs...> {};
template<size_t...szs>
struct sequence_maker<0,szs...> {
using type = index_sequence<szs...>;
};
}
template<size_t Count>
using make_index_sequence=typename details::sequence_maker<Count>::type;
template<class...Ts>
using index_sequence_for=make_index_sequence<sizeof...(Ts)>;
and this alias:
template<class Sig>
using result_of_t=typename std::result_of<Sig>::type;
then strip std:: off their use in the above code.
live example.
Boost variant does something like what you are doing. It lets you replace switch statements with a template based contruct that can check that all cases are defined at compile-time, but then select one at run-time.
e.g.,
using namespace boost;
using Data = variant<int, double>;
struct ProcessDataFn: static_visitor<void>
{
char* data;
void operator()(int& i)
{
// do something with data
}
void operator()(double& d)
{
// do something else
}
};
void processData(char* data, Data& dataOut)
{
apply_visitor(ProcessDataFn{data}, dataOut);
}
void example(char * data)
{
Data d = 0;
processData(data, d); // calls first overload of operator()
Data d = 0.0;
processData(data, d); // calls second overload
}
To expand on my comment, ideally we'd have compile-time reflection and be able to write a generic dispatch function. In its absence, one option is to unfortunately use macros to do that for you using the X Macro pattern:
#define LIST_OF_CASES \
X_ENUM(kValue0) \
X_ENUM(kValue1) \
X_ENUM(kValue2)
enum MyEnum
{
# define X_ENUM(a) a,
LIST_OF_CASES
# undef X_ENUM
};
void dispatch(MyEnum val)
{
switch (val)
{
# define X_ENUM(a) case a: processData<a>(); break;
LIST_OF_CASES
# undef X_ENUM
default:
// something's really wrong here - can't miss cases using this pattern
}
}
One benefit of this approach is that it scales to large numbers of enumerations, it gets really hard to omit a case, and that you can attach extra information by using a multi-argument X_ENUM macro.
I know you said you'd like to avoid macros, but the alternative without virtual functions then is to have some sort of a static table of function pointers indexed by the enum, and that is just a virtual function in disguise (with admittedly lower overhead, but still suffering the cost of an indirect function call).

Compile time optimization - removing debug prints from release binaries

It is my very first post, so I would like to welcome with everybody. The problem I have occurred is the code optimization at compilation time, and to be more specific removing debug prints.
Let's imagine that we have native syslog logger and we are wrapping it (without using of macros, it is very important note!) with following code:
enum severity { info_log, debug_log, warning_log, error_log };
template <severity S>
struct flusher {
logger* log_;
flusher(logger* log) : log_(log) {}
flusher(flusher& rhs) : log_(rhs.log_) {}
~flusher() { syslog(S, log_->stream.str()); log_->stream.str(""); }
operator std::ostream& () { return log_->stream; }
};
#ifdef NDEBUG
template <> struct flusher<debug_log> {
flusher(logger*) {}
flusher(flusher&) {}
~flusher() {}
template <typename T> flusher& operator<<(T const&) { return *this; }
};
#endif
struct logger {
std::ostringstream stream;
template <severity T>
flusher<T> operator<<(flusher<T> (*m)(logger&)) { return m(*this); }
};
inline flusher<info_log> info(logger& log) { return flusher<info_log>(&log); }
inline flusher<debug_log> debug(logger& log) { return flusher<debug_log>(&log); }
inline flusher<warning_log> warning(logger& log) { return flusher<warning_log>(&log); }
inline flusher<error_log> error(logger& log) { return flusher<error_log>(&log); }
I thought that the empty implementation of flusher will encourage compiler to remove such useless code, but with both O2 and O3 it is not removed.
Is there any possibility to provoke mentioned behaviour?
Thanks in advance
I have successfully done what you're attempting, although with at least two differences... 1) I wasn't using templates - that might be creating a complexity the compiler is unable to optimize out, and 2) my log use included a macro (see below).
Additionally, you may have already done this, make sure all your "empty" definitions are in the logger's header file (so optimizations are done at compile-time and not postponed to link-time).
// use it like this
my_log << "info: " << 5 << endl;
The release definition looks like this:
#define my_log if(true);else logger
and the debug definition looks like this:
#define my_log if(false);else logger
Note that the compiler optimizes out the logger for all if(true) in release, and uses the logger in debug. Also note the full if/else syntax in both cases avoids funny situations where you have unscoped use, e.g.
if (something)
my_log << "this" << endl;
else
somethingelse();
would cause somethingelse to be the else of my_log without it.
Your current code is not preventing the call to f() and any side effects it may have, only preventing the actual printing. This is why macros are the traditional approach to this problem - they provide an unevaluated context where you can check if the value should be printed before actually printing.
In order to achieve this without macros, some extra indirection is needed e.g. std::function, function pointers etc. As an example, you could provide a wrapper class which contained a std::function, and specialise your stream operators to call the std::function in the default case, and not in the NDEBUG case
Very rough example:
//Wrapper object for holding std::functions without evaluating
template <typename Func>
struct debug_function_t {
debug_function_t(Func & f) : f(f) {}
decltype(f()) operator()() { return f(); }
std::function<Func> f;
};
//Helper function for type deduction
template <typename Func>
debug_function_t<Func> debug_function(Func & f) {
return debug_function_t<Func>(f);
}
struct debug_logger {
template <typename T>
debug_logger & operator<<(T & rhs) {}
template <typename Func> //Doesn't call f(), so it's never evaluated
debug_logger & operator<<(debug_function_t<Func> f) { }
};
Then in your client code
int f(){ std::cout << "f()\n"; }
debug_logger log;
log << debug_function(f);
So, following the comment's code:
inline int f()
{
std::cout << 1;
return 1;
}
needs to be made into:
inline int f()
{
#ifndef NDEBUG
std::cout << 1;
#endif
return 1;
}
or something like this:
#ifndef NDEBUG
static const int debug_enable = 1;
#else
static const int debug_enable = 0;
#endif
inline int f()
{
if (debug_enable)
{
std::cout << 1;
}
return 1;
}
You need to tell the compiler somehow that this code isn't needed.
The technique I've used for a few games requires the debug printing to be a function rather than a general expression. E.g.:
debug_print("this is an error string: %s", function_that_generates_error_string());
In release mode, the definition of debug_print is:
#define debug_print sizeof
That removes debug_print and any expression passed to it from the executable. It still has to be passed valid expressions, but they are not evaluated at runtime.

static if in plain c++?

Problem in short:
How could one implement static if functionality, proposed in c++11, in plain c++ ?
History and original problem:
Recently I came up with a problem like this. I need a class Sender with an interface like
class Sender
{
void sendMessage( ... );
void sendRequest( ... );
void sendFile( ... );
// lots of different send methods, not important actually
}
In some cases I will need to create a DoubleSender, i.e. an instance of this class, which would call its methods twice, i.e. when calling, let's say, a sendMessage(...) method, the same message has to be sent twice.
My solutions:
First approach:
Have an isDouble member, and in the end of each method call make a check
sendMessage(...) { ... if( isDouble ) { sendMessage( ... ); }
Well, I don't want this, because actually I will need double posting very recently, and this part of code in time-critical section will be 98% passive.
Second approach:
Inherit a class DoubleSender from Sender, and implement its methods like:
void DoubleSender::sendMessage( ... )
{
Sender::sendMessage(...);
Sender::sendMessage(...);
}
Well, this is acceptable, but takes much space of unpleasant code (really much, because there are lots of different send.. methods.
Third approach:
Imagine that I am using c++11 :). Then I can make this class generic and produce the necessary part of code according to tempalte argument using static if:
enum SenderType { Single, Double };
template<SenderType T>
class Sender
{
void sendMessage(...)
{
// do stuff
static if ( T == Single )
{
sendMessage(...);
}
}
};
This is shorter, easier to read than previous solutions, does not generate additional code and... it's c++11, which I unfortunately cannot use in my work.
So, here is where I came to my question - how can I implement static if analog in c++ ? Also, I would appreciate any other suggestions about how to solve my original problem.
Thanks in advance.
Quoting #JohannesSchaubLitb
with my static_if that works on gcc one can do it :)
in some limited fashion
(see also here)
This trick involves a specific GCC interpretation of the specs on Lambdas in C++11. As such, it will (likely) become a defect report against the standard. This will lead to the trick no longer working in more recent version of GCC (it already doesn't work in 4.7).
See the comment thread below for some more details from Johanness
http://ideone.com/KytVv:
#include <iostream>
namespace detail {
template<bool C>
struct call_if { template<typename F> void operator<<(F) { } };
template<>
struct call_if<true> {
template<typename F>
void operator<<(F f) { f(); }
};
}
#define static_if(cond) detail::call_if<cond>() << [&]
template<bool C, typename T>
void f(T t) {
static_if(C) {
t.foo();
};
}
int main() {
f<false>(42);
}
Why not make the send implementation a policy of the sender class and use CRTP:
template<class Derived>
class SingleSenderPolicy
{
public:
template< class memFunc >
void callWrapperImpl(memFunc f, ...)
{
static_cast<Derived *>(this)->f(...);
}
};
template< class Derived >
class DoubleSenderPolicy
{
public:
template< class memFunc >
void callWrapperImpl(memFunc f, ...)
{
static_cast<Derived *>(this)->f(...);
static_cast<Derived *>(this)->f(...);
}
};
template< class SendPolicy>
class Sender : public SendPolicy< Sender >
{
public:
void sendMessage( ... )
{
// call the policy to do the sending, passing in a member function that
// acutally performs the action
callWrapperImpl( &Sender::sendMessageImpl, ... );
}
void doSomethingElse( ... )
{
callWrapperImpl( &Sender::doSomethingElseImpl, ... );
}
protected:
void sendMessageImpl(... )
{
// Do the sending here
}
void doSomethingElseImpl(... )
{
// Do the sending here
}
};
The public sendXXX functions in you class simply forward to the call wrapper, passing in a member function that implements the real functionality. This member function will be called according to the SendPolicy of the class. CRTP saves the use of bind to wrap the arguments and this pointer up with the member function to call.
With one function it doesn't really cut down on the amount of code, but if you have a lot of calls it could help.
Note: This code is a skeleton to provide a possible solution, it has not been compiled.
Note: Sender<DoubleSenderPolicy> and Sender<SingleSenderPolicy> are completely different types and do not share a dynamic inheritance relationship.
Most compilers do constant folding and dead code removal, so if you write a regular if statement like this:
enum SenderType { Single, Double };
template<SenderType T>
class Sender
{
void sendMessage(...)
{
// do stuff
if ( T == Single )
{
sendMessage(...);
}
}
};
The if branch will get removed when the code is generated.
The need for static if is when the statements would cause a compiler error. So say you had something like this(its somewhat psuedo code):
static if (it == random_access_iterator)
{
it += n;
}
Since you can't call += on non-random access iterators, then the code would always fail to compile with a regular if statement, even with dead code removal. Because the compiler still will check the syntax for before removing the code. When using static if the compiler will skip checking the syntax if the condition is not true.
std::string a("hello world");
// bool a = true;
if(std::is_same<std::string, decltype(a)>::value) {
std::string &la = *(std::string*)&a;
std::cout << "std::string " << la.c_str() << std::endl;
} else {
bool &la = *(bool*)&a;
std::cout << "other type" << std::endl;
}