6

I have logging function being called at several places throughout the code. To every log, I have to supply 2 compile time constants. There are 2 approaches to accomplish:

(1) Function argument:

template<typename T>
void log (const T &obj, const int LINE, const int COUNT)
{
  // T is used for some purpose
  if(debug)
    logging(obj.out(), LINE, COUNT);
}

call it as,

log(str, __LINE__, __COUNTER__);

(2) Template parameter:

template<typename T, int LINE, int COUNT>
void log (T &obj)
{
  // T is used for some purpose
  if(debug)
    logging(obj.out(), LINE, COUNT);
}

call it as,

log<__LINE__, __COUNTER__>(str);

I am not able to decide, because 1st approach offers simplicity, but we are passing constant at compile time. 2nd approach is perfect, but compilation time would probably increase. This task is tedious, and I haven't implemented any of them yet, so I don't have any bench mark.

It will be a great help if someone can answer this from their experience/knowledge.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 1
    How do you define "better"? They both *work*, so what criteria would you use to say that one is better than the other? – Nicol Bolas Dec 19 '11 at 06:59
  • @NicolBolas, as I want to choose the better among 2 based on compilation time and runtime. Also there is a slight modification in the example code. – iammilind Dec 19 '11 at 07:04
  • Whatever that `logging` function does, it will *most certainly* be slower than passing two integers as arguments. So I don't see how the runtime performance will change very much either way. This sounds suspiciously like a premature optimization. – Nicol Bolas Dec 19 '11 at 07:06
  • 1
    @Nichol: "it will most certainly be slower than passing two integers as arguments" - I don't think that's certain at all in the case where `debug` is false. It may well still be negligible, of course. – Steve Jessop Dec 19 '11 at 10:30

2 Answers2

4

Since the choice between these two makes a difference to the calling code, I would recommend logging via a macro. Then you don't have to worry now about which of these is better, because it's easy to switch between them.

Once you have your real application written, you can mess with the macro definition to compare the two. Or not, if there are more productive areas to optimize. If it turns out to make a big difference, you can even leave it open to the build config to decide whether to use -DLOGGING_COMPILES_QUICKLY or -DLOGGING_RUNS_QUICKLY.

Another potential benefit of a macro: you could arrange that the first argument is evaluated if and only if debug is true. I don't know what the interface of str is, or where those objects come from, but if it costs anything to produce the right value to pass to log, and then log doesn't use it in the non-debug case, then that's a potential waste of runtime.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • Nice answer... Most of the times LINE & COUNT will not be used. Which alternative is better in that case fir production code? – iammilind Dec 19 '11 at 15:04
  • @iammilind: If `debug` is a compile-time constant, and the call to `log` is inlined, then the emitted code probably should be the same either way, although that's a QOI issue. If you want to know the details for a particular implementation, check the disassembly. – Steve Jessop Dec 19 '11 at 15:16
3

I would go with the first option. The performance impact of passing two integers is negligible. The optimizer will also probably inline the function call in which case there would be no difference between the two. The second option I think is a bad idea, since you will be creating a lot of versions of the same function, for no reason.

ronag
  • 49,529
  • 25
  • 126
  • 221
  • Ok, there is a slight modification in the question syntax. The `log` itself is a `template` function, I thought of not mentioning it ... but found that it would be useful. Also, wouldn't compiler will optimize away the several versions of `template log` too ? – iammilind Dec 19 '11 at 07:03
  • Well there will only be a few versions of the first log function, std::string, std::wstring, char*, wchar_t*. While basically every function call to the second version will result in a new function. The optimizer will probably handle it, but you will get the same result with longer compilation time. – ronag Dec 19 '11 at 07:10