Wednesday, January 29, 2014

Koenig Lookup and Stream Operator

Today I met with a wired problem with my C++ code. It tooks me several hours to fix it and it turns out it is related to Koeing Lookup and Name Hidding.

Problem

Here is the sample code that has problem.

#include <iostream>

namespace A {
    struct Foo { int data; };
}

namespace B {
    template<typename T>
    void output(const T& t) { std::cout << t; }

    struct Bar { int data; };
    std::ostream& operator<< (std::ostream& stream, const Bar& bar) {
        return stream << bar.data; 
    }
}

std::ostream& operator<< (std::ostream& stream, const A::Foo& foo) {
    return stream << foo.data; 
}

int main() {
    A::Foo foo;
    B::output(foo);
}

I got the following compilation error with it. Basially the compiler complains that it can’t find the operator<<(std::ostream&, const A::Foo&) function.

c:\path\main.cpp:9: error: C2679: binary '<<' : no operator found which takes a right-hand operand of type 'const A::Foo' (or there is no acceptable conversion)

Solution

The fix is simply moving operator<<(std::ostream&, const A::Foo&) into namespace A.

Why?

Listed below are why the error occurs, and why the fix works.

Basically speaking, when C++ compiler tries to find an unqualified function, it will search in two different ways:

  • A: Search the namespacs from the one where the function is called up to the global namespace (also take into account of using namespace and using) until found.
    • For example, in the sample code, it will search for the operator<<(std::ostream&, const A::Foo&) function both B and global namespaces.
  • B: Koenig lookup - search in the set of associated namespaces of all its argument types.

    • For example, in the sample code, it will search for the operator<<(std::ostream&, const A::Foo&) function in the following two namespaces:

      • std, the namespace of the first argument type ostream
      • A, the namespace of the second argument Foo
    • Here is the definition on Wikipedia of Koenig Lookup.

      In the C++ programming language, argument-dependent lookup (ADL), or argument-dependent name lookup, applies to the lookup of an unqualified function name depending on the types of the arguments given to the function call.

In the sample code, since the function operator<<(std::ostream&, const A::Foo&) can be found using method A, then it should work. But it does not!!!

The problem is that there is already a function operator<< in namespace B. Though it has different signature from the one we are looking for, compiler simply stop searching up. That is why the function can’t be found. Basically, it is because of Name Hiding.

The reason why the fix works is that once we move the function into namespace A, then it can be found using method B. So basically it is because of Koenig Lookup.

Monday, January 27, 2014

STL documentation in QtCreator

The post shows how to enable STL documentation in QtCreator.

  • Go to http://en.cppreference.com/w/Cppreference:Archives and download the latest Qt help book
  • Extract the .qtc file out of the achive downloaded
  • Open QtCreator, go to Tools -> Options -> Help -> Documentation tab
  • Click Add button and select the .qtc file
  • Restart QtCreator

That’s it. You could now move your cursor to a STL keyword and press F1 to view its documentation.

Friday, January 24, 2014

Example to Use Boost.Log

The following code is an example that illustrates how to use Boost.Log.

Several Notes:

  • In the example, debug_output_backend (e.g. DebugView, or Visual Studio Output Pane) is used. It support multi-process logging. It is only available on Windows. On linux, syslog_backend is a good alternative.
  • Log level control is implemented using a global varable g_log_level and a boost log filter function log_level_filter.
  • Messages can be logged by send them to log streams, e.g. LOG(), LOG_ERROR.
  • All the items that output to log stream should support operator<<(std::ostream&) or operator<<(boost::log::record_ostream&)

See also Boost.Log

#include <iostream>
#include <iomanip>
#include <string>
#include <boost/log/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/sinks/debug_output_backend.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/phoenix/bind/bind_function_object.hpp>
#include <boost/log/support/date_time.hpp>

using namespace std;
using namespace boost;
using namespace boost::log;

namespace {

    // log severity level
    enum log_level {
        Debug,
        Info,
        Warning,
        Error
    };

    // logger type with severity level and multithread support
    typedef sources::severity_logger_mt<log_level> logger_t;

    // windows debugger output (e.g. DbgView) sink type with synchronization support
    typedef sinks::synchronous_sink<sinks::debug_output_backend> sink_t;

    // global variables
    log_level g_log_level = Info;  // log level
    logger_t* g_logger; // logger

    // define the keywords to use in filter and formatter
    BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", log_level)
    BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", 
        attributes::local_clock::value_type)
    BOOST_LOG_ATTRIBUTE_KEYWORD(processid, "ProcessID", 
        attributes::current_process_id::value_type)
    BOOST_LOG_ATTRIBUTE_KEYWORD(threadid, "ThreadID", 
        attributes::current_thread_id::value_type)

    // the filter used to filter log records according to level
    bool log_level_filter(value_ref<log_level, tag::severity> const& level) {
        return level >= g_log_level;
    }

    // stream output support for log_level
    std::ostream& operator<<(std::ostream& stream, log_level level) {
        static const char* strings[] = { "debug", " info", " warn", "error" };
        int l = static_cast<size_t>(level);
        if (l >= 0 && l < sizeof(strings) / sizeof(strings[0]))
            stream << strings[l];
        else
            stream << l;
        return stream;
    }

    void initialize_logger() {
        // create a logger
        g_logger = new logger_t();

        boost::shared_ptr<core> core = core::get();

        // add attributes
        core->add_global_attribute("TimeStamp", attributes::local_clock());
        core->add_global_attribute("ProcessID", attributes::current_process_id());
        core->add_global_attribute("ThreadID", attributes::current_thread_id());

        // add level filter
        core->set_filter(phoenix::bind(&log_level_filter, severity.or_none()));

        // create a debug output sink
        boost::shared_ptr<sink_t> sink(new sink_t());

        // sink formatter
        sink->set_formatter(expressions::stream
            << "[" << processid << "]"
            << "[" << threadid << "]"
            << "[" << expressions::format_date_time(
                                        timestamp, "%Y-%m-%d %H:%M:%S") << "]"
            << "[" << severity << "] "
            << expressions::smessage);

        // add sink
        core->add_sink(sink);
    }

    void cleanup_logger() {
        if (g_logger) {
            delete g_logger;
            g_logger = nullptr;
        }
    }

    // macros to get log streams
    #define LOG_DEBUG()     BOOST_LOG_STREAM_SEV(*g_logger, Debug) \ 
        << __FUNCTION__ << "(): "
    #define LOG_INFO()      BOOST_LOG_STREAM_SEV(*g_logger, Info) \ 
        << __FUNCTION__ << "(): "
    #define LOG_WARNING()   BOOST_LOG_STREAM_SEV(*g_logger, Info) \ 
        << __FUNCTION__ << "(): "
    #define LOG_ERROR()     BOOST_LOG_STREAM_SEV(*g_logger, Error) \ 
        << __FUNCTION__ << "(): "
    #define LOG()           LOG_INFO()
}

void doSomething() {
    LOG() << "Log message from doSomethng()";
}

int main(int argc, char** argv) {
    initialize_logger();

    LOG() << "Application started";
    LOG_ERROR() << "An error occured";
    doSomething();

    LOG_DEBUG() << "This message won't be log if g_log_level >= Info";
    g_log_level = Debug;
    LOG_DEBUG() << "This message will be log if g_log_level >= Debug";

    cleanup_logger();
    return 0;
}

Sunday, January 19, 2014

Build Qt 5.2 with Visual C++ 2013

Prerequisites

Steps

  • Extract Qt Source to c:\build\qt-everywhere-opensource-src-5.2.0
  • Extract ICU to c:\build\icu
  • Setup Visual C++ Environment
  • Add Python, Ruby, Perl to PATH
  • Add GnuWin32 to PATH
    set PATH=%PATH%;c:\build\qt-everywhere-opensource-src-5.2.0\gnuwin32\bin

  • Add ICU to INLCUDE, LIB, PATH
    set INCLUDE=%INCLUDE%;c:\build\icu\inlcude
    set LIB=%LIB%;c:\build\icu\lib
    set PATH=%PATH%;c:\build\icu\lib

  • Configure
    configure -platform win32-msvc2013 -release -shared -c++11 -opensource -confirm-license -nomake tests -nomake examples -make-tool jom

  • Build
    jom

Sunday, January 5, 2014

Remove Files From Git History

The following command is treat to be the nuclear weapon in Git. It can be used to remove files from history.

git filter-branch --force --index-filter \
  'git rm --cached --ignore-unmatch tmp/*' \
  --prune-empty --tag-name-filter cat -- --all

Please change tmp/* in the command line to any file patterns you need.

Friday, January 3, 2014

Info about GCC Versions

Just a quick note about GCC versions and C++ 11 support.

http://gcc.gnu.org/projects/cxx0x.html

GCC version and libstdc++.so version mapping

http://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html

Remove Git Commit and Clean up Repository

When using Git, sometimes we may find we are in situations that some changes (or files) were commited by mistake and we want to remove them permanently from the repository. Listed below are the steps to do that.

For example, we have following configuration. We committed three changes and we want to remove the second one (with hash bbbbbb).

HASH     COMMENTS
aaaaaa   Initial commit
bbbbbb   The commit we want to remove
cccccc   Some other changes

To remove the bbbbbb, we can use git rebase command. One way to use it is as follows.

git rebase --onto bbbbbb^ bbbbbb

Another (safer, I think) way is to use git rebase -i aaaaaa. The command will open up a VIM editor, in which each commit after aaaaaa lies in a single line.

pick bbbbbb   The commit we want to remove
pick cccccc   Some other changes

To remove commit bbbbbb, we can simply delete the line pick bbbbbb, save and exit VI (:wq).

Now, if you run git log you would not see bbbbbb any more. But the disk space occupied by the commit is not release yet. That is because Git has reflog feature, that will keep unreachable objects for a period of time (3 months initially?). The following command can be used to release the disk space at once. Think again before you run it!

git reflog expire --all --expire-unreachable=now
git fsck --unreachable
git gc --aggressive --prune=now

The are many other usages of git rebase -i. For example, change comments, combine two commits to one, etc. Please refer to its document for more details.

Thursday, January 2, 2014

Qt5 DEPENDPATH Breaking Changes

Today when trying to build an old project with Qt5, I got a lot of warning and errors like the one below.

WARNING: Failure to find: foo.cpp
...
Error: dependent 'foo.cpp' does not exist.

The warnings and errors are about the lines in a foo.pri file.

INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += foo.h
SOURCES += foo.cpp

In my project, foo.pri exists in the same directory of foo.cpp and foo.h. With Qt4, wherever the foo.pri is included, the foo.cpp and foo.h will be added to source file list and header file list respectfully.

But obviously this won’t work with Qt5. After some googling, I found this post. Basically there is breaking changes of DEPENDPATH in qmake that shipped with Qt5.

Though it is far from being an elegant solution, the following lines fix the issue.

INCLUDEPATH += $$PWD
HEADERS += $$PWD/foo.h
SOURCES += $$PWD/foo.cpp