I'm working on a bare-metal embedded system, with a class that can be compiled for different hardware versions. The class takes in a pointer to a device and uses it, or takes in NULL if the device is not present on that hardware.

When the device is not present, I want the device code to be left out of the compiled binary, to save space. I can use #defines, but that gets messy. I can create multiple copies of my class, but that is not as maintainable. Is there a better solution to this problem?



#include "my_class.hh"

int main()
    My_Class my_class(NULL);


    return 0;


#include "device.hh"

class My_Class
    My_Class(Device* device = NULL);

    void perform_tasks();


    Device* m_device;


#include "my_class.hh"

My_Class::My_Class(Device* device)
: m_device(device)


void My_Class::perform_tasks()
    if(m_device != NULL)

    // perform other tasks
  • Is that NULL a literal? – Deduplicator May 21 at 22:01
  • I believe my GCC version defines it as 0, so yes I suppose it would be. – Marlon Smith May 21 at 22:10
  • Which C++ version can you use? – Deduplicator May 21 at 22:47
  • I'm not using C++11, I believe it would be C++03 – Marlon Smith May 22 at 16:27

The Null Object Pattern would fit perfectly here (https://en.m.wikipedia.org/wiki/Null_object_pattern).

You want an object with all the methods that doesn't do anything. That way you can call methods in this object without testing to see if the device exists. Create a sub class called NullDevice or NonExistentDevice that defines all the same methods as the real thing but these methods wouldn't do anything. Then just use it.

Now you can reduce your compile time directives to one that decides which device to use: the real one or fake one.

  • There is still all the code calling it though. And that's what OP wants to cut out in an elegant way. – Deduplicator May 21 at 22:13
  • This solution would save space on the chip, which is one of the biggest concerns here. – Marlon Smith May 21 at 22:18

If there is much code whose execution shall be dependent on some compile-time constant, consider using lambdas, and isolating the choice in a single member using if constexpr:

template <class F>
inline constexpr auto exec_on_device(F f) noexcept(!MY_DEVICE || noexcept(f()))
-> decltype((void)f())
    if constexpr (MY_DEVICE)
        if (m_device)

exec_on_device([&]{ m_device->use(); });

Yes, the null object pattern can help.

But instead of creating an additional dummy device type, use a dummy pointer type.
Somewhere in the config file:

using DEVICE_PTR = dummy_ptr<Device>;
using Device_PTR = Device*;

For implementation, see std::experimental::observer_ptr, aka the world's dumbest smart-pointer, and lobotomize it:

#include <cassert>

template <class T>
struct dummy_ptr {
    using element_type = T;
    constexpr dummy_ptr() noexcept = default;
    constexpr dummy_ptr(std::nullptr_t) noexcept {}
    constexpr dummy_ptr(T* p) noexcept { assert(!p); }
    constexpr T* release() noexcept { return nullptr; }
    constexpr void reset(std::nullptr_t = {}) noexcept {}
    constexpr void reset(T* p) noexcept { assert(!p); }
    constexpr void swap(dummy_ptr) noexcept {}
    constexpr T* get() const noexcept { return nullptr; }
    constexpr explicit operator bool() const noexcept { return false; }
    constexpr T& operator*() const noexcept { return *operator->(); }
    constexpr T* operator->() const noexcept { assert(0); return nullptr; }
    constexpr explicit operator T*() const noexcept { return nullptr; }

// Plus some more supporting free functions
  • I appreciate both of your answers. I should have specified in the question that I'm not using C++11, so while these look like good solutions I'm not able to use them. Edit: Updated the question to specify C++03. – Marlon Smith May 22 at 16:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.