Some time ago, I proposed Using type aliasing to avoid the ODR problem with conditional compilation. A Reddit thread claimed that “It’s weak functions basically. You can actually achieve this without needing templates but need to separate the weak and non-weak definitions.”
I’m not seeing how weak functions help here, but maybe somebody can set me straight.
Weak functions are still functions. If you are changing data layout (as we are in our case of adding a Logger member), you can weaken any functions that access the data members, but that doesn’t help any class consumers that access those data members, because the data member accesses are inlined into the call site.
Let’s look at our Widget again.
// widget.h
struct Widget { Widget();
void SetName(std::string const& name);
⟦ more stuff ⟧
#ifdef EXTRA_WIDGET_DEBUGGING Logger m_logger;
void Log(std::string const& message) {
m_logger.log(message);
}
#else void Log(std::string const& message) { // no extra logging } #endif
std::string m_name;
};
If somebody just accesses the name directly:
void sample(Widget& w) { std::cout << w.m_name; }
The access to w.m_name is inlined into the sample function. It’ll probably go something like
mov rsi, edi ; rsi -> Widget
#ifdef EXTRA_WIDGET_DEBUGGING add rsi, 16 ; offset of m_name ; if there is a Logger #else add rsi, 24 ; offset of m_name ; if there isn’t a Logger #endif mov rdi, offset std::cout call operator<< ; print the name to cout
The compiler is going to inline the offset to m_name, so it will choose an offset based on whether the EXTRA_WIDGET_DEBUGGING symbol is set. But if the caller is building with EXTRA_WIDGET_DEBUGGING set the opposite way, then you are printing garbage.
The idea behind templating the Widget based on whether it is debugging or not is to allow parts of the code to use a debugging Widget, but other parts to use a non-debugging Widget.
template<bool debugging> struct WidgetT { ⟦ … ⟧ };
#ifdef EXTRA_WIDGET_DEBUGGING using Widget = WidgetT<true>; #else using Widget = WidgetT<false>; #endif
The pieces that use a debugging widget get WidgetT<true>, and those that don’t get a WidgetT<false>.
While weak pointers let you provide two versions of a function (say, debugging and non-debugging), you can’t have both versions active at the same time. Everybody has to agree on whether it’s a debugging version or a non-debugging version.
But maybe I’m missing something. If you can explain how to accomplish this with weak functions, let me know in the comments.
Bonus chatter: Another downside of weak functions is that they aren’t inlined, but maybe link time optimization can re-inline them.
The post Maybe somebody can explain to me how weak references solve the ODR problem appeared first on The Old New Thing.
From The Old New Thing via this RSS feed


