Switching to C++11
All the *mm projects now require C++11. Current versions of g++ require you to use the –std=c++11 option for this, but the next version will probably use C++11 by default. We might have done this sooner if it had been clearer that g++ (and libstdc++) really really supported C++11 fully.
I had expected that switching to C++11 would require an ABI break, but that has not happened, so already-built applications will not be affected. But our API now requires C++11 so this is a minor API change that you will notice when rebuilding your application.
Some distros, such as Fedora, are breaking the libstdc++ ABI slightly and requiring a rebuild of all applications, but that would have happened even without the *mm projects moving to C++11. It looks like Ubuntu might be doing this too, so I am still considering taking advantage of a forced (not gtkmm’s fault) widespread ABI break to make some ABI-breaking changes in gtkmm.
C++11 with autotools
You can use C++11 in your autotools-based project by calling AX_CXX_COMPILE_STDCXX_11() in your configure.ac after copying that m4 macro into your source tree. For instance, I used AX_CXX_COMPILE_STDCXX_11() in glom. The *mm projects use the MM_AX_CXX_COMPILE_STDCXX_11() macro that we added to mm-common, to avoid copying the .m4 file into every project. You may use that in your application instead. For instance, we used MM_AX_CXX_COMPILE_STDCXX_11() in the gtkmm-documentation module.
C++11 features
So far, the use of C++11 in gtkmm doesn’t provide much benefit to application developers and you can already use C++11 in applications that use older versions of gtkmm. But it makes life nicer for the gtkmm developers themselves. I’m enjoying learning about the new C++11 features (particularly move constructors) and enjoying our discussions about how best to use them.
I’m reading and re-reading Scott Meyer’s Effective Modern C++ book. C++11’s rvalue references alone require great care and understanding.
For now, we’ve just made these changes to the **mm projects:
- Using auto to simplify the code.
For instance,
auto builder = Gtk::Builder::create(); - Using range-based for-loops.
For instance,
for(const auto& row : model->children()) { … } - Using nullptr instead of 0 or (void*)0.
For instance,
Gtk::Widget* widget = nullptr; - Using the override keyword when we override a virtual method.
For instance,
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override; - Using noexcept instead of throw().
For instance,
virtual ~Exception() noexcept; - Using “= delete” instead of private unimplemented copy constructors and operator=().
- Using C++11 lambdas, instead of sigc::slots, for small callback methods.
See below.
libsigc++ with C+11
libsigc++ has also moved to C++11 and we are gradually trying to replace as much as possible of its internals with C++11. Although C++11 has std::function, there’s still no C++11 equivalent for libsigc++ signals and object tracking
You can use C++11 lambda functions with libsigc++. For instance, with glibmm/gtkmm signals:
button.signal_clicked().connect( Â [] () { Â Â Â std::cout << "clicked" << std::endl; } );
And now you don’t need the awkard SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE macro if the signal/slot returns a value. For instance:
m_tree_model_filter->set_visible_func( [this] (const Gtk::TreeModel::const_iterator& iter) -> bool { auto row = *iter; return row[m_columns.m_col_show]; Â } );
With C++14 that should be even nicer:
m_tree_model_filter->set_visible_func( [this] (auto iter) -> decltype(auto) { auto row = *iter; return row[m_columns.m_col_show]; } );
These -> return type declarations are necessary in these examples just because of the unusual intermediate type returned by row[].