6

I'd like to check during compile time if some function of some class is used/not used, and accordingly fail/pass the compilation process.

For example if function F1 is called somewhere in the code I want the compilation to succeed, and if function F2 is called I want it to fail.

Any ideas on how to do that, with usage of preprocessor, templates or any other c++ metaprogramming technique?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Max Shifrin
  • 809
  • 9
  • 24
  • 1
    "If F1 is called it shall succeed" is a strange requirement. Do you mean: "If F1 is *not* called it shall fail to compile"? – Daniel Frey Sep 15 '13 at 14:57
  • @JoachimPileborg Ahm, fair enough, I retract my comment. –  Sep 15 '13 at 15:00
  • Another problem: "At compile-time..." - but the function might be used in a different translation unit! – Daniel Frey Sep 15 '13 at 15:04
  • 4
    rename the function, the linker will tell you if its used. – mah Sep 15 '13 at 15:06
  • Should be checked at compile-time? It could be easily checked at runtime – Manu343726 Sep 15 '13 at 15:09
  • 1
    There is no way for the *compiler* to tell if an external function is called or not, only functions defined in the translation unit currently being compiled. I haven't found any suitable command line option for that (the `-Wunused-function` only warns about non-inline `static` functions). I haven't seen anything appropriate in among the linker flags either. You might have to make the linker create a map file, and if it contains that information then parse that file and issue a build-process error. – Some programmer dude Sep 15 '13 at 15:17
  • 3
    Can you tell us more about *why* you want that? I'm pretty sure there is a better solution for the *actual* problem. – us2012 Sep 15 '13 at 15:18
  • I didn't say the code was coming from some external translation unit. But this could be quite a lot of code to track changes and make sure no one is doing anything _italic_ bad_italic_ with it. – Max Shifrin Sep 16 '13 at 04:42

2 Answers2

6

You can achieve this with a c++11 compiler provided you are willing to modify F2 to include a static_assert in the function body and add a dummy template to the signature:

#include <type_traits>

void F1(int) {    
}

template <typename T = float>
void F2(int) {
    static_assert(std::is_integral<T>::value, "Don't call F2!");
}

int main() {
 F1(1);  
 F2(2);  // Remove this call to compile
}

If there are no callers of F2, the code will compile. See this answer for why we need the template trickery and can't simply insert a static_assert(false, "");

Community
  • 1
  • 1
  • ... and remove the old implementation of `F2`. – Angew is no longer proud of SO Sep 15 '13 at 15:36
  • There is no need to remove the old implementation, just modify the existing one. –  Sep 15 '13 at 15:40
  • 1
    ... and move it to the header. If you don't, you'll get errors of undefined template at call site (instead of the `static_assert` firing). Still good enough for "compile-time error if `F2` is called", I guess. – Angew is no longer proud of SO Sep 15 '13 at 15:50
  • Agreed; I forgot to take that into account in my example. It's probably less hassle to just rename the function per the comment from @mah to achieve the compile-time error. –  Sep 15 '13 at 15:55
  • Looks like a good direction... How about making this a bit more complicated :-) Say I have a set of functions F1...Fn and a set of classes C1...Cm Is there a way for me to make the code compile/not compile under a known rule set where for each class Ci it is allowed to call only a subset of the functions F1..Fn (different subset for each class. Also making things even more complicated, what if I want soundness. Meaning - making sure that some function *is* called from somewhere. – Max Shifrin Sep 16 '13 at 04:40
  • the drawback is that turning `F2(int)` into a template affects overload resolution. Suddenly `F2(somthing)` might call a different `F2`. – 463035818_is_not_an_ai Oct 16 '20 at 19:26
1

Not a very templatey solution, but instead you can rely on compiler's deprecated attribute that will generate warning if a function is used anywhere.

In case of MSVC you use __declspec(deprecated) attribute:

__declspec(deprecated("Don't use this")) void foo();

G++:

void foo() __attribute__((deprecated));

If you have "treat warnings as errors" compile option on (which you generally should) you'll get your desired behaviour.

int main() 
{
    foo(); // error C4966: 'foo': Don't use this
    return 0;
}
gwiazdorrr
  • 6,181
  • 2
  • 27
  • 36