gtkmm now uses C++11

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[].

17 thoughts on “gtkmm now uses C++11

  1. Another thing you might want to use in the mm-projects: ‘= delete’ syntax instead of private special functions with no implementation, e.g. for copy constructors if a class is meant to be non-copyable (but this can also be used for other things like disabling weird default comparison operator behaviour of two objects of a class that doesn’t have comparison operators but has an implicit cast operator to a type that does have comparison operators).

    Also, a small thing about the example code block with the lambda without arguments: You can leave out the parentheses for the arguments there, they are only required if they’re non-empty.

    1. Yes, we are using = delete. I forgot to mention it, but I’ll add a bullet point for it now.

      And thanks for the comment about the parentheses. I didn’t know that. I think I’ll leave them there for now. For me, parentheses make something look like a method call.

  2. Hi Why not you use C++14 right away? Why use C++11 it is outdated and old school. Even C++14 is getting close to outdated with C++17 around the corner. But C++14 is still latest C++. If people can use C++11 then people can use C++14 or they can use their C++11 to compile new version of GCC or Clang that support C++14. So why not go for the future and go right to C++14 and skip C++11?

    1. Wich C++14 features would you use? C++11 isn’t “outdated”, it’s just that there are even more new features with C++14.

      1. You need to read the article! Read the part that starts with “With C++14 that should be even nicer:”! It will give you the example that you want!

        1. As I see it that is a usage of the gtkmm library. You can of course use C++14 in your code when calling gtkmm even if that only uses C++11. As long as gtkmm accepts a lambda there it is irrelevant how the lambda was constructed (as long as your compiler supports C++14).

          But what C++14 features would you use in the API of gtkmm?

          1. I would use member initialization in aggregate for lists and trees. I would use constexpr more for constant expressions. I would use generic lambdas for event handling. I would use expressional capture by lambda for event handling too. I would use the deprecated attribute for marking old functionality that will be gone in future releases. I would use user defined literals. I would use std::cbegin and std::cend for iterating over list boxes and lists of widgets. See there are many uses for C++14 for things that C++11 just cannot do so well!

        2. Interesting. Yes, those things would be nice, but it doesn’t make C++11 “outdated”, because it builds on C++11. It doesn’t replace C++11 features (which is what I expect when I hear the word “outdated”) but adds new. But yes, it would be nice.

          1. If C++11 can’t do it but C++14 can then by definition C++11 is outdated compared to C++14.

  3. Hi!

    This is great news and I’m sure it’s going to make it even nicer to work with Gtkmm!

    One comment about your lambda examples though. C++11 does already support type deduction for the return types of lambda expressions (using the rules of auto as oposed of those of decltype(autio)). You mention that because of the type of the row thingy it’s not possible to write something like this, that would seem otherwise valid C++11:

    m_tree_model_filter->set_visible_func(
    [this] (const Gtk::TreeModel::const_iterator& iter) {
    auto row = *iter;
    return row[m_columns.m_col_show];
    }
    );

    Could you elaborate on why is that the case? Also, would you prefer using a signature declarator to:

    m_tree_model_filter->set_visible_func(
    [this] (const Gtk::TreeModel::const_iterator& iter) {
    auto row = *iter;
    return bool{row[m_columns.m_col_show]};
    }
    );

    Cheers!

  4. Well, it certainly makes me happy that C++11 is going places and helps people write better code, and it most certainly particularly warms my heart that people find override useful. :)

Leave a Reply to Ville Voutilainen Cancel reply

Your email address will not be published. Required fields are marked *