0

I have a logging class (a singleton) and every call to it looks like this:

SomeNamespace::Logger::instance().log(SomeNamespace::Logger::Priority::Error, "log info %d %d %d", 1, 2, 3);

Is it possible to shorten this call in C++14?

I don't want to use #define if there is a more elegant way to do it but I can't figure it out by myself.

EDIT: what I really want is to create a set of function aliases for different logging levels for the call to look like:

LogInfo("log info %d %d %d", 1, 2, 3);
LogError("log info %d %d %d", 1, 2, 3);
  • 3
    [Namespace alias](https://stackoverflow.com/q/1211399/10077), maybe? – Fred Larson Aug 14 '17 at 13:53
  • @Nikolay Kovalenko You can use a using declaration. – Vlad from Moscow Aug 14 '17 at 13:53
  • 1
    Is something like `auto &logger = SomeNamespace::Logger::instance(); logger.log(...);` what you are asking for? – Baum mit Augen Aug 14 '17 at 13:54
  • 2
    there are multiple ways to do that - usings, functions, wrappers, local variables. IMO you would really have to be more specific as to what "short" means to you – default Aug 14 '17 at 13:57
  • 1
    Using macros does have advantages for logging. With them, you can turn logging on/off selectively for debugging, at .the cpp level, for example. Macros are a bit like goto, they should not be abused, but they sure have some unique properties that can be very useful. – Michaël Roy Aug 14 '17 at 14:06

3 Answers3

1

Import the namespace like this

using SomeNamespace

or this

using SomeNamespace::Logger

Edit:

The easiest to achieve something like:

LogInfo("log info %d %d %d", 1, 2, 3);
LogError("log info %d %d %d", 1, 2, 3);

Is to create a facade for the Logger class, that does all the dirty work for you and import it with a using directive.

Matt
  • 116
  • 6
0

Sorry at work just throwing in ideas :)

From here C++11: How to alias a function? you could declare a function alias using perfect forwarding?

template <typename... Args>
auto g(Args&&... args) -> decltype(f(std::forward<Args>(args)...)) {
    return f(std::forward<Args>(args)...);
}

or

#include <iostream>

namespace Bar
{
   void test()
   {
       std::cout << "Test\n";
   }


   template<typename T>
   void test2(T const& a)
   {
      std::cout << "Test: " << a << std::endl;
   }
}

void (&alias)()        = Bar::test;
void (&a2)(int const&) = Bar::test2<int>;

int main()
{
    Bar::test();
    alias();
    a2(3);
}
ervinbosenbacher
  • 1,720
  • 13
  • 16
0

If you want to achieve

LogInfo("log info %d %d %d", 1, 2, 3);
LogError("log info %d %d %d", 1, 2, 3);

Then you may want just to write some wrapper functions around your original Logger. Like this:

void LogInfo(const char* fmt...) {
    SomeNamespace::Logger::instance().log(SomeNamespace::Logger::Priority::Info, fmt);
}

void LogError(const char* fmt...) {
    SomeNamespace::Logger::instance().log(SomeNamespace::Logger::Priority::Error, fmt);
}

But if you want to reduce code duplication and automatically generate all these functions depending on your Priority contents, then I do not see any way except macro, because there is no mechanisms in C++ to generate function declarations with different names. Sorry, but I can only advise this solution:

#define DeclareLogFunction(LEVEL) \
    void Log##LEVEL(const char* fmt...) { \
        SomeNamespace::Logger::instance().log(SomeNamespace::Logger::Priority::LEVEL, fmt); \
    }

DeclareLogFunction(Debug)
DeclareLogFunction(Info)
DeclareLogFunction(Error)
DeclareLogFunction(Critical)


int main(){
    LogError("log info %d %d %d", 1, 2, 3);
}

Also, you probably might be interested in this approach:

template <SomeNamespace::Logger::Priority P>
void Log(const char* fmt...) {
    SomeNamespace::Logger::instance().log(P, fmt);
}

int main() {
    Log<SomeNamespace::Logger::Priority::Info>("log info %d %d %d", 1, 2, 3);
}

It breaks your desired code a bit, but looks fine for me, and no macros.

Nikolai Shalakin
  • 1,349
  • 2
  • 13
  • 25
  • Or you can use function aliases. Here is a detailed explanation https://stackoverflow.com/questions/3053561/how-do-i-assign-an-alias-to-a-function-name-in-c, C++11 and C++14 has even more to offer. But I like the simplicity of wrapper functions. as above. – ervinbosenbacher Aug 14 '17 at 15:02