Re: Support service

2022-02-14 Thread Jonathan Wakely via gtkmm-list
On Mon, 14 Feb 2022 at 20:17, Martin Owens  wrote:

> On Mon, 2022-02-14 at 20:08 +0000, Jonathan Wakely via gtkmm-list
> wrote:
> > People work on them for free,
>
> No,  people work on them for lots of money; they distribute them for
> free.
>

Well I think it's a bit of both, in practice. I doubt every contributor to
gtkmm is paid to do so.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Support service

2022-02-14 Thread Jonathan Wakely via gtkmm-list
On Mon, 14 Feb 2022, 19:50 David Gasa i Castell via gtkmm-list, <
gtkmm-list@gnome.org> wrote:

> Dear project team,
>
> I write you to say that it doesn't work.
>

This is a useless statement. Nobody can help something so vague, what does
"doesn't work" mean?


> I've been using Gtkmm libraries since 2.x (even if some refactorings and
> changes were made thereafter) but I still need your help.
>
> Having a reference helps but it's not enough.
>
> When I submitted questions directly to the project programmers, they
> pointed me to submit in a list...
>

That's how open source projects usually work. People work on them for free,
but they don't want strangers contacting them directly expecting support.
The mailing list is the right way to seek help.



but a list that nobody has the responsibility to answer in an appropriate
> manner... does not help, either. Silence does not help.
>
> I'd like to know, if possible, why some of my questions (and other users'
> as well), if so, are not properly answered and how to solve it.
>

Make sure you are asking good questions.

http://www.catb.org/~esr/faqs/smart-questions.html


> I should ask you to improve the support.
>
> Is it possible to create a payment subscription quotes or on demand
> service in order to receive assistance ?
>

It took me less than ten seconds to find this page:

https://gtkmm.org/en/commercial_support.html
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Additional Glib::RefPtr Safety Mechanism

2019-09-01 Thread Jonathan Wakely via gtkmm-list
On Sat, 31 Aug 2019, 11:55 Karsten Pedersen,  wrote:

> I have yet to see it in any gtkmm code (you will be pleased to hear)
> but my personal opinion is that it is surely a nice idea to attempt
> to make C++ 100% safe rather than having to rely purely on the skills of
> a developer. This is generally the trend in Rust communities but it
> seems the culture in C++ communities is that not all safety is
> necessary.
>

With Rust that safety is checked and enforced by the language and the
compiler. The language rules mean that most checking can have no overhead
at runtime. Your solution incurs non-zero runtime cost (extra reference
counting) which can't be optimised away in general.

Being 100% safe would be nice, but there's a trade off. Achieving it in C++
is either impossible or very expensive. I don't agree that "it is surely a
nice idea to attempt to make C++ 100% safe". It's unrealistic to pretend
otherwise.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Additional Glib::RefPtr Safety Mechanism

2019-08-30 Thread Jonathan Wakely via gtkmm-list
On Thu, 29 Aug 2019 at 21:27, Karsten Pedersen  wrote:

> Hi all,
>
> One area of C++ that always frustrates me is safety. Smart pointers
> such as the Glib::RefPtr go a good way to avoid dangling pointers, use
> after free, etc. However one area where this (and std::shared_ptr) is
> lacking is that it is very easy for "this" to dangle and there really
> is no protection against it. Check out a very simple example here:
>
> https://github.com/osen/sr1/blob/master/src/tests/dangling_this.cpp
>
>
Is this actually a common problem that needs to be solved?

It seems like a solution in search of a problem. IMO you should just avoid
using globals like this when possible, and use them carefully when
necessary.

For the shared_ptr example, you can solve the problem simply by copying the
global into a local variable in the one function that needs to do it. That
way you don't pay the cost in every function that uses operator->

  void broken()
  {
auto keepalive = d;
d = std::sr1::shared_ptr();
dummy = 9;
  }

That keeps *this alive until the end of the function.

Or slightly more efficiently:

  void broken()
  {
auto keepalive = std::move(d);
d = std::sr1::shared_ptr();
dummy = 9;
  }
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: C++17

2018-04-14 Thread Jonathan Wakely
On 14 April 2018 at 15:38, Murray Cumming wrote:
> On Thu, 2018-04-12 at 21:10 +0100, Jonathan Wakely wrote:
>> On 12 April 2018 at 21:02, Murray Cumming wrote:
>> > I've just released a version of libsigc++-3.0 (currently unstable)
>> > that
>> > requires C++17. This means that gtkmm-4.0 (currently unstable)
>> > requires
>> > C++17 too. I should have mentioned it first, but I think this is
>> > fine.
>>
>> What are you using from C++17?
>
> Nothing major. Just some constexpr if, std::apply() and std::invoke():
> https://github.com/libsigcplusplus/libsigcplusplus/commits/master

That's fine then - no ABI worries with those bits.

>> GCC's C++17 implementation is not stable yet, so there are still ABI
>> changes possible between GCC 8 and GCC 9.
>>
>> IIRC we've already introduced some (minor) incompatibilities between
>> the std::variant in GCC 7 and GCC 8.
>
> gtkmm-4.0 is itself unstable, so that's not a problem. And I see no
> sign that GTK+ 4.0 will become stable any time soon.

OK, cool. I wanted to be sure you wouldn't end up with a dependency on
something unstable, but it sounds like that won't be a problem.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: C++17

2018-04-12 Thread Jonathan Wakely
On 12 April 2018 at 21:02, Murray Cumming wrote:
> I've just released a version of libsigc++-3.0 (currently unstable) that
> requires C++17. This means that gtkmm-4.0 (currently unstable) requires
> C++17 too. I should have mentioned it first, but I think this is fine.

What are you using from C++17?

GCC's C++17 implementation is not stable yet, so there are still ABI
changes possible between GCC 8 and GCC 9.

IIRC we've already introduced some (minor) incompatibilities between
the std::variant in GCC 7 and GCC 8.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: get/set wrap methods.

2018-02-23 Thread Jonathan Wakely
On 23 February 2018 at 14:55, Pavlo Solntsev wrote:

> Daniel,
>
> now it is clear. I didn't and still don't understand exactly how internal
> data members are represented in the generated class (I have no access to my
> code now) but the situation I have by returning a reference is clear. BTW
> does it make sense to think about shared_ptr as returned value for getter?
>


No, because unless you keep a copy of the shared_ptr as a member, you will
get a new shared_ptr each time you call it, which doesn't share ownership
with the previous ones.

So now you have the shared_ptr overhead (reference counting) and
inconvenience (needing to use operator* to access the value), without any
sharing.

You might as well just return by value, or have a Glib::ustring member.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: get/set wrap methods.

2018-02-23 Thread Jonathan Wakely
On 23 February 2018 at 14:37, Jonathan Wakely wrote:

> On 23 February 2018 at 14:22, Pavlo Solntsev wrote:
>
>> Yes, I did. because my goal is to get
>> const T& get_name()const
>> method. I need to return a reference.
>>
>>
> Then you need to change your type to have a using member.
>

Sorry, for the typo, that was meant to say "ustring member"



>
> You can't have it both ways (return a reference, but not have something to
> bind the reference to).
>
> Pick one.
>
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: get/set wrap methods.

2018-02-23 Thread Jonathan Wakely
On 23 February 2018 at 14:22, Pavlo Solntsev wrote:

> Yes, I did. because my goal is to get
> const T& get_name()const
> method. I need to return a reference.
>
>
Then you need to change your type to have a using member.

You can't have it both ways (return a reference, but not have something to
bind the reference to).

Pick one.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: LInking problems after switch to gcc-6.4.0

2018-01-08 Thread Jonathan Wakely
On 8 January 2018 at 10:19, Daniel Boles wrote:
> I guess it's probably this:
> https://stackoverflow.com/a/33395489/2757035

Yup, GCC 5+ has two versions of std::string, to link functions using
std::string both the caller and callee need to agree on which version
of std::string is used. Everything needs to be compiled consistently,
to use the same version of std::string.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Why do Glib::ustring::operator[] and at() return values, not references?

2017-06-28 Thread Jonathan Wakely
On 28 June 2017 at 09:39, Daniel Boles wrote:
> But the main drawback I could think of is this: It would change semantics
> for anyone currently using auto some_character = non_const_ustring[N], as
> the auto would now capture the proxy type, not a gunichar. To get the
> latter, the type would have to be explicitly specified to invoke the
> conversion operator. Or is there a clever way around this that I don't know?

There's no way around it. There have been proposals for an "operator
auto" that would make it possible to control the deduced type, mostly
for use by expression templates, but nothing that is part of C++ yet.

Another downside of a proxy is it can outlive the string, so this
would be undefined (without some internal complexity to track
lifetimes):

auto c = Glib::ustring("foo")[0];
c = 'b';  // tries to modify the expired temporary

Again, this only happens when using 'auto' because otherwise there's
no attempt to write back into the ustring:

gunichar c = Glib::ustring("foo")[0];
c = 'w'; // just modifies c
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: C++17's string_view (was Re: Making use of move semantics?)

2017-06-13 Thread Jonathan Wakely
On 13 June 2017 at 08:31, Murray Cumming wrote:

>
> So, I think:
> 1. We would use std::string_view everywhere if all the C functions took
>   a length instead of assuming null-termination. That's not going to
> happen.
>
> 2. Overriding all methods to take either a const char* or a std::string
> (ignoring ustring for now), would avoid the extra array copy, but I
> don't think it's worth it other than for methods that typically take
> very large strings.
>
> 3. GTK+ functions that take very large strings tend to take a length,
> to avoid the need for copying. For instance,
> gtk_text_buffer_set_text(). We could take std::string_view there, but
> then our use of std::string_view::to_string() would be wasteful when
> someone passes a std::string to our method.
>
> This is discouraging, so I hope I'm wrong about something.
>
>

Nope, you're correct. string_view is great if you stay in C++ world, but
suboptimal when you need to pass the string to libc functions or C APIs
taking null-terminated strings.

One possible approach (which I have no experience of in practice, only in
theory) is to use string_view objects which explicitly include the
null-terminator in their length:

template
inline std::basic_string_view
make_null_terminated_view(const C* s) noexcept
{ return { s, T::length() + 1 }; }

template
inline bool
is_null_terminated_view(std::basic_string_view sv) noexcept
{ return sv.length() && !sv.back(); }


And/or create your own cstring_view / zstring_view type which is guaranteed
to be null-terminated:

struct cstring_view : std::string_view {
  cstring_view(const char* s)
  : std::string_view(s, traits_type::length(s)+1)
  { }
};

Unlike std::string which has a null-terminator after its content that isn't
counted in the length, these string views would count the null character as
part of their content. You'd need a little more care to use this (i.e. when
using the length remember to subtract one where appropriate) but it does
mean you can pass around views to null-terminated strings efficiently
(along with their length, which is the advantage over a raw pointer).
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: enums that are really just sets of constants

2017-05-23 Thread Jonathan Wakely
On 23 May 2017 at 15:29, Daniel Boles  wrote:

>
> On 23 May 2017 at 15:12, Kjell Ahlstedt  wrote:
>
>>
>> I don't understand how you can have, for instance
>>   void f(ResponseType r);
>> if ResponseType is an uninstantiable class. If ResponseType is the name
>> of a class, and you want to treat it as if it were the name an enum,
>> wouldn't it require something like
>>
>
> D'oh. Right! Carry on. :)
>
> The language seems to make this overcomplicated. I need to search for info
> on whether anyone ever proposed a scoped but implicitly convertible enum,
> and if so, why it never got anywhere.
>


Then we'd have three types of enum ... that doesn't seem like it'd be an
improvement.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: enums that are really just sets of constants

2017-05-23 Thread Jonathan Wakely
On 23 May 2017 at 08:51, Kjell Ahlstedt  wrote:

> Den 2017-05-13 kl. 10:04, skrev Kjell Ahlstedt:
>
> Yet another suggestion in https://bugzilla.gnome.org/
> show_bug.cgi?id=86864#c43
>
> Can we decide what to do with the few enums that we want to be implicitly
> convertible to int? My suggestion in https://bugzilla.gnome.org/
> show_bug.cgi?id=86864#c43 is
>
>   class ResponseType_Enum final
>   {
>   public:
> enum ResponseType
> {
>   NONE = -1,
>   REJECT = -2,
>   ACCEPT = -3,
>   ...
> };
> ResponseType_Enum() = delete;
>   };
>   using ResponseType = ResponseType_Enum::ResponseType;
>
> I tried to make a mixture of a plain (old-style) enum and an enum class.
> It shall be implicitly convertible to int, and its enumerators shall be
> scoped. In other respects it shall be possible to use it as if it's an
> enum, e.g.
>
>   ResponseType r = ResponseType::REJECT;
>   int i = r;
> but not
>   r = REJECT;
>   i = REJECT;
> and preferably not
>   r = i;
>
> Daniel has remarked that _Enum is not a good suffix for a class name. I
> agree. Can you think of a better suffix? I don't want to call the class
> *ResponseType*. That would clash with *using ResponseType = ...*. If it
> shall be possible to use *ResponseType* as if it's the name of an enum,
> it must be the name of an enum or an alias for a name of an enum. Or are
> there other possibilities that are not too complicated?
>

Would Response::Type work?

struct Response final
{
  enum Type { ... };
  Response() = delete;
};

void foo(Response::Type = Response::REJECT);
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Making use of move semantics?

2017-05-22 Thread Jonathan Wakely
On 21 May 2017 at 10:36, Daniel Boles wrote:

> I still occasionally find myself reflexively std::move()ing strings into
> glibmm/gtkmm functions that I unconsciously see as taking ownership of
> their arguments - only to realise it makes no difference because all of
> them take strings as const&.
>
> This made me wonder whether there are any cases where, if the user
> instructs so by using std::move(), glibmm/gtkmm functions could steal the
> string [ or at least it's c_str() ] and thus avoid having to copy it. All
> those copies quickly add up to a lot.
>

You can't steal the contents of a std::string without access to its
internals, which only the standard library has. You can't steal the c_str()
... I'm not even sure what that would mean.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: enums that are really just sets of constants

2017-05-08 Thread Jonathan Wakely
On 7 May 2017 at 15:10, Kjell Ahlstedt <kjellahlst...@gmail.com> wrote:
> Den 2017-05-06 kl. 23:09, skrev Jonathan Wakely:
>
> On 6 May 2017 at 21:00, Murray Cumming <murr...@murrayc.com> wrote:
>
> The old style-enum won't let us change this, in gtkmm 3,
>
> Gtk::RESPONSE_OK
> into this, in gtkmm 4:
> Gtk::Dialog::Response::OK
> without also polluting the API with this
> Gtk::Dialog::OK
>
> Using an old-style enum would let us have this:
> Gtk::Dialog::RESPONSE_OK,
> (and Gtk::Dialog::Response::RESPONSE_OK)
> which is still an improvement, but not quite as nice.
>
> Strictly speaking, an old-style enum *and* a scope would allow that.
>
> namespace Gtk {
>   struct Dialog {
> struct Response {
>   enum ResponseEnum { OK };
> };
>   };
> }
>
> That would give you the implicit conversions of old-style enums, but
> still give scoped names. That might not be useful, I'm just saying
> it's possible.
> ___
>
> That might very well be useful. A minor drawback is that we would have both
> Gtk::Dialog::Response::OK (wanted) and
> Gtk::Dialog::Response::ResponseEnum::OK (unwanted). With an unnamed
> old-style enum there would be only Gtk::Dialog::Response::OK.
>
> namespace Gtk {
>   class Dialog : public ... {
>   public:
> struct Response {
>   enum { OK };
> };
>   };
> }
>
> An unnamed enum entails some restrictions, as discussed in
> https://bugzilla.gnome.org/show_bug.cgi?id=86864#c34, but that's probably
> not important for the very few enums in gtkmm and other mm-modules where we
> want implicit conversion to int.

Personally I find the downsides of unnamed enumerations types (can't
overload on the type, don't have a name to refer to the constants even
though they are allegedly related) are much worse than the fact there
are two ways to refer to the enumerations. I've never seen problems
arising from the fact that you could also write
Gtk::Dialog::Dialog::Dialog::Dialog::Response::OK (because of the
injected-class-name) so I don't see why the case you mentioned would
be a real problem.

If you're really worried about it:

namespace Gtk {
  class Dialog : public ... {
  public:
struct Response {
  enum ResponseEnum { };
  static constexpr ResponseEnum OK = 0;
  static constexpr ResponseEnum ERR1 = 1;
  static constexpr ResponseEnum ERR2 = 2;
};
  };
}

But I don't think that's an improvement.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: enums that are really just sets of constants

2017-05-06 Thread Jonathan Wakely
On 6 May 2017 at 21:00, Murray Cumming  wrote:
> On Sat, 2017-05-06 at 18:08 +0100, Daniel Boles wrote:
>> So it seems that the only option is to continue using C-style enums
>> within classes, e.g. class Dialog { enum ResponseType{} } as
>> present.. As someone already mentioned, I see no problem with this:
>> such an enum is not inherently bad in itself; it's only bad if chosen
>> in o s case where another solution (enum class, constexpr, etc.) is
>> an available and more appropriate option. As that does not apply, the
>> C-style enum should continue to serve this purpose well.
>
> The old style-enum won't let us change this, in gtkmm 3,
> Gtk::RESPONSE_OK
> into this, in gtkmm 4:
> Gtk::Dialog::Response::OK
> without also polluting the API with this
> Gtk::Dialog::OK
>
> Using an old-style enum would let us have this:
> Gtk::Dialog::RESPONSE_OK,
> (and Gtk::Dialog::Response::RESPONSE_OK)
> which is still an improvement, but not quite as nice.

Strictly speaking, an old-style enum *and* a scope would allow that.

namespace Gtk {
  struct Dialog {
struct Response {
  enum ResponseEnum { OK };
};
  };
}

That would give you the implicit conversions of old-style enums, but
still give scoped names. That might not be useful, I'm just saying
it's possible.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: enums that are really just sets of constants

2017-04-22 Thread Jonathan Wakely
On 22 April 2017 at 05:57, Dr. Diether Knof wrote:
> Hello,
>
> for the integer wraps used for flags I have a third proposition, a working 
> example is attached:
> * "enum class DisplayOption" for the individual flags
> * "class DisplayOptions" with an implicit converter DisplayOption -> 
> DisplayOptions
> So we get an enum for the single options and avoid the old enum-style.

Why not have the constants declared inside the class, so you only have
one name to remember, not DisplayOption and DisplayOptions?

You can overload operator| and operator& for enums, so the only
benefit to this seems to be the implicit conversion to bool (why not
explciit?)
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: enums that are really just sets of constants

2017-04-19 Thread Jonathan Wakely
On 19 April 2017 at 11:51, Kjell Ahlstedt wrote:
> Den 2017-04-19 kl. 12:24, skrev Murray Cumming:
>
> On Wed, 2017-04-19 at 10:30 +0100, Jonathan Wakely wrote:
>
> You can also use a namespace to give them their own scope, which has
> less overhead than a class type (no RTTI for the class, no way for
> users to create instances of the class type, or pointers to it, which
> would have no purpose if it's just being used to create a new scope
> for the enumerators).
>
> Good point.
>
> I'm leaning towards this at the moment.
>
> Is it possible to define a namespace within a class?

No.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: enums that are really just sets of constants

2017-04-19 Thread Jonathan Wakely
On 19 April 2017 at 09:37, Murray Cumming wrote:
> In the ABI-breaking versions of glibmm and gtkmm, we have recently
> changed the enums to be C++11 "enum class"s. This is generally a
> welcome improvement.
> - Their values are, for instance, Things::ONE, rather than THINGS_ONE.
> - Their values do not convert implicitly to other types such as int or
> bool, helping the compiler to find some programmer mistakes.
>
> We are also gradually moving the enums inside classes when they are
> typically only used with that class.
>
> However, some of the C enums that we wrap are actually meant to be
> integer constants, so it seems that we cannot and should not use "enum
> class" for these.

How are they used? Are they compared to integers? Are they passed to
gtk APIs that expect integers?

You can use scoped enums anyway, but you'd need an explicit cast to an
integer, so it might not be appropriate.

> So I wonder what is the most "modern C++" way to do
> this while keeping the new-style syntax. Here are two possibilities:
>
> 1. Use old-style enums inside a class:
>
> class ResponseType {
> public:
>   enum Enum {
> NONE = -1,
> REJECT = -2,
> ACCEPT = -3,
> ...
>   };
> };

You can also use a namespace to give them their own scope, which has
less overhead than a class type (no RTTI for the class, no way for
users to create instances of the class type, or pointers to it, which
would have no purpose if it's just being used to create a new scope
for the enumerators).

> But shouldn't we just avoid old-style enums completely?

Why? Both types still have uses in modern C++. Old doesn't mean bad.

N.B. since C++11 you can use the enumeration type's name as a
qualification even for unscoped (i.e. old-style, non-class) enums:

enum E { Foo, Bar, Baz };

auto e = E::Foo;

So you can use the new syntax even with old-style enums. The problem
is that you're not *required* to do that, you can still just say Foo,
so the names still leak into the surrounding scope. With a scoped
(i.e. new-style, class) enum the qualification is required.


> 2. Use constexpr int constants inside a class:
>
> class ResponseType {
> public:
>   constexpr int NONE = -1;
>   constexpr int
> REJECT = -2;
>   constexpr int ACCEPT = -3;
>   ...
> };
>
> But shouldn't we use some kind of enum to group the values together?

Is their type actually important? i.e. are these different values of
the same logical type? If yes, then using an enumeration makes sense.
Otherwise just using an enumeration type to create an arbitrary group
doesn't add any benefit.

The example above looks like these are different values for the same
"thing" so giving them the same type makes sense to me. It allows
overloading on that type, for example.

Aside: IMHO the shouty ALL_CAPS naming is not good style in C++, see
https://accu.org/index.php/articles/1923 for my reasoning.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Supporting C++17

2017-04-04 Thread Jonathan Wakely
On 4 April 2017 at 23:37, Chris Vine wrote:
> Aha, this may be it.
> http://en.cppreference.com/w/cpp/language/noexcept_spec also says:
> "Functions differing only in their exception specification cannot be
> overloaded (just like the return type, exception specification is part
> of function type, but not not part of the function signature) (since
> C++17)."
>
> So I suspect that the noexcept specification may still not affect name
> mangling.

Right. See the foo and bar examples.

You can't overload like this:

void f() noexcept;
void f();

But you can overload like this:

void g(void(*)());
void g(void (*)() noexcept);

The mangled name of a function doesn't depend on its exception
specification. It does depend on the parameter types (as it always has
in all versions of C++) and the parameter types can now be affected by
exception specifications.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Supporting C++17

2017-04-04 Thread Jonathan Wakely
On 4 April 2017 at 23:28, Chris Vine <ch...@cvine.freeserve.co.uk> wrote:
> On Tue, 4 Apr 2017 23:09:33 +0100
> Jonathan Wakely <gt...@kayari.org> wrote:
>> On 4 April 2017 at 22:56, Chris Vine wrote:
>> > I would check that.  It didn't affect ABI in C++11/14, but I am not
>> > so sure about C++17.  According to
>> > http://en.cppreference.com/w/cpp/language/noexcept_spec,
>> > in C++17 "The noexcept-specification is a part of the function type
>> > and may appear as part of any function declarator."  If it is part
>> > of the type then it might feature in name mangling, so this is
>> > worth checking with the compiler writers.
>>
>> In C++17 the exception spec is part of the type, so noexcept(true)
>> functions are mangled differently from functions that are
>> noexcept(false).
>
> As I said in my follow-up email, on reflection I agree with you about
> noexcept(false).
>
> But if this is correct about noexcept(true), and I am now beginning to
> doubt myself on this, then it seems a recipe for broken libraries.  It
> makes any code with a noexcept(true) function specification which has
> been compiled with the -std=c++14 option ABI incompatible with the same
> code compiled with the -std=c++17 option.

Not any code, only code that depends on the type of function pointers
in mangled names. The mangled names of the functions themselves don't
change, only names that depend on them.

Using https://godbolt.org/g/akduU4 again, foo anr bar do not change
their mangled names. But f2, which depends on decltype(), does
change.

However, it's uncommon to actually use decltype() like that in a
function signature. Far more common would be something like:

using func_type = void(*)();
void f2(func_type);

And this wouldn't change, because func_type doesn't include the
exception specification (because it wasn't allowed to in C++14).

There's an implicit conversion from R(*)(Args...) noexcept to
R(*)(Args...) so calling f2() would still work whether it's
declared to take void(*)() or void(*)()noexcept.

Some code may well be affected, and we don't know exactly how much,
but it's not as catastrophic as you suggest. It's a good reason not to
require C++17 for glibmm yet though :-)



> What benefit accrues from making the noexcept specification part of
> the type which is worth all that ABI breakage?

See my previous email.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html
also gives some (terse) rationale.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Supporting C++17

2017-04-04 Thread Jonathan Wakely
On 4 April 2017 at 23:08, Chris Vine wrote:
> On second thoughts, noexcept(true) might possibly change ABI in C++17,
> but it seems inconceivable that noexcept(false) would.

Right.

You can verify this fairly easily:

https://godbolt.org/g/akduU4

Notice that the type of foo (as used in the type of f1) is the same
for c++98, c++14 and c++17.

The type of bar (as it shown in the type of f2, which godbolt's
demangler doesn't even support!) changes for c++17.

foo is a noexcept(false) function, and is the same whether it uses
throw(bad_cast) or noexcept(false).

bar is a noexcept(true) function, and is the same whether it uses
throw() or noexcept(true), but is not the same for c++17 comapred with
earlier versions.

But what makes a difference is -std=c++17, not whether you use
throw(...) or noexcept(...).

>  It also seems
> weird that merely applying -std=c++17 to your code should break its
> ABI.  The more I think about it, the less clear I am what making the
> noexcept specification part of the function type in C++17 actually
> involves compiler-wise, or what it achieves.

It allows overloading on whether a function can throw, and
specializing templates on it, and deducing it from template arguments.

So if you take the address of a function you don't lose it's
"noexceptiness". Previously this static assertion could never pass:

void f() noexcept;
template void g(F f) {
static_assert( noexcept( f() ), "callback won't throw" );
}

int main() {
g(  );
}

In C++17 it compiles.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Supporting C++17

2017-04-04 Thread Jonathan Wakely
On 4 April 2017 at 22:56, Chris Vine wrote:
> I would check that.  It didn't affect ABI in C++11/14, but I am not so
> sure about C++17.  According to
> http://en.cppreference.com/w/cpp/language/noexcept_spec,
> in C++17 "The noexcept-specification is a part of the function type and
> may appear as part of any function declarator."  If it is part of the
> type then it might feature in name mangling, so this is worth checking
> with the compiler writers.

In C++17 the exception spec is part of the type, so noexcept(true)
functions are mangled differently from functions that are
noexcept(false).

But functions with dynamic exception specification aren't
noexcept(true), so they're not mangled as noexcept(true) functions
would be.

If you replace the throw(std::bad_cast) with neoxcept(false) (or,
equivalently, omit the exception specification entirely) they still
aren't noexcept(true).

Here's the proof:
https://paste.fedoraproject.org/paste/Pwm-rv4LGXKh2EDVJSeOEl5M1UNdIGYhyRLivL9gydE=/

N.B. I didn't say that exception specifications don't affect the type,
I said that removing the deprecated dynamic exception specification,
i.e. throw(std::bad_cast), doesn't affect the type. Because it's still
a noexcept(false) function.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Supporting C++17

2017-04-04 Thread Jonathan Wakely
On 4 April 2017 at 15:09, Jonathan Wakely wrote:
> On 4 April 2017 at 14:52, Murray Cumming wrote:
>> Noticed here:
>> https://bugzilla.redhat.com/show_bug.cgi?id=1438766

From that bug report:

(In reply to Murray Cumming from comment #6)
> This makes sense: C++17 will remove support for old-style exception
> specifications, so we'd need some cleverness to support both the old and new
> ways in glibmm. I guess this will break lots of C++ code.

Why try to support the old way?

Dynamic exception specifications are not very useful, and have been
recommended against for many many years. Simply removing them (so the
functions are implicitly noexcept(false)) shouldn't break any code.

Even if you have virtual functions using throw(X), user code that
overrides them would still compile if you removed them:

struct X {
  virtual void f() noexcept(false) { }
};

struct Y : X {
  void f() throw(int) { }
};

This is still OK, because the Y::f override has a stricter exception
specification.


The other way around doesn't work. If you have throw(std::bad_cast) on
a virtual function then users who override it are forced to also use a
deprecated dynamic exception specification, they can't use
noexcept(false):

struct X {
  virtual void f() throw(int) { }
};

struct Y : X {
  void f()  noexcept(false) { }
};

v.cc:6:8: error: looser throw specifier for ‘virtual void Y::f()
noexcept (false)’
  void f()  noexcept(false){ }
   ^
v.cc:2:16: error:   overriding ‘virtual void X::f() throw (int)’
  virtual void f() throw(int) { }
   ^

(I don't see any uses on virtual functions in glibmm or gtkmm so this
might not be a problem anyway).

Simply removing them from your headers seems the best solution.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Supporting C++17

2017-04-04 Thread Jonathan Wakely
On 4 April 2017 at 14:52, Murray Cumming wrote:
> Any ideas about how we should support C++17 in gtkmm-3.0 without losing
> C++11/14 compatibility and without breaking ABI?

Replace all dynamic exception specifications with noexcept(false) (or
just no exception specification). That's not an ABI change.


> Or should we require C++17 for later gtkmm-3.0 versions?

I think that would be premature, GCC support for it is still experimental.

> Noticed here:
> https://bugzilla.redhat.com/show_bug.cgi?id=1438766
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: gtkmm 4: Glib::ustring: implicit conversions with streams

2016-12-20 Thread Jonathan Wakely
On 20 December 2016 at 09:26, Kjell Ahlstedt wrote:
>
> The conversions done by Glib::ustring are reasonable, at least if the read
> or written stream uses the global locale. A std::locale contains a codecvt
> facet, used for converting between one character encoding in the stream
> (file) and a possibly different character encoding in main memory. But
> Glib::ustring shall always contain UTF-8 encoded characters, independent of
> the stream's locale and codecvt facet. It's reasonable that ustring's
> operator<<() and operator>>() convert between UTF-8 and the stream's main
> memory encoding.

I get horribly confused by C++ locales, and especially the character
encoding parts, but I think streams expect to receive characters in
the native character set, so I think using the global locale is
correct. That gives you a conversion from UTF-8 to the native
character set, which gives you something in the encoding that streams
expect.

When a stream wants to perform a conversion using its imbued locale it
already knows how to do that, e.g. std::filebuf does that so that
bytes written to a file are converted from the in-memory encoding to
the on-disk encoding.

But as I said, I find this stuff very confusing.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Bug in documentation: Gio::File Class Reference

2016-08-03 Thread Jonathan Wakely
On 3 August 2016 at 23:38, Alwin Leerling wrote:
> I believe I may have found some errors in the reference documentation
> of the Gio::File Class:
>
> Function signatures
>
> std::string Gio::File::get_basename() const
> std::string Gio::File::get_path() const
> std::string Gio::File::get_relative_path(
> const Glib::RefPtr< const File & descendant >
> ) const
> std::string Gio::File::get_uri() const
>
> are all declared returning a const std::string.

No they aren't, those return non-const std::string objects.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Shouldn't Glib::ustring::raw() return const char* ?

2016-08-02 Thread Jonathan Wakely
On 2 August 2016 at 07:03, John Emmas wrote:

> I just updated my compiler to VS2015 after using VS2005 for many years.  I
> built a small test app and linked it to my DLLs (which are still built with
> the older compiler).  Ultimately, they'll be getting built with the new
> compiler and I was aware of some things to avoid (such as not allocating
> memory in a DLL and trying to release it in the new app etc).  But I didn't
> anticipate the problem with std::string.  Consider this example:-
>
>   void some_func()
>   {
> std::string test = Glib::get_application_name();
>   }
>
> 'test' is a std::string in the format expected by VS2015 - whereas (in my
> case) the call to 'get_application_name()' returns a std::string in the
> format that was known to VS2005 - so calling that function from my new app
> is guaranteed to crash my program.  I figured that if I could obtain the
> application name in a POD char array, that might help - and I quickly
> discovered that this change seemed fix things:-
>
> std::string test = Glib::get_application_name().c_str();
>
> but when I mentioned it on a popular programming forum, someone pointed
> out that if the above was working, that was purely a case of luck.
>

Why is it purely a case of luck? Because get_application_name() returns a
std::string by value, which tries to copy the VS2005 type using the code
from VS2015?
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Problem using std::prev on ustring iterator

2016-03-19 Thread Jonathan Wakely
On 18 March 2016 at 18:11, Jonathan Wakely <gt...@kayari.org> wrote:
> On 18 March 2016 at 17:57, jeremy.harmon wrote:
>> Hello,
>>
>> When I try to use std::prev on a ustring const_iterator nothing
>> happens, operator-- works fine.
>>
>> Glib::ustring str = "test";
>> Glib::ustring::iterator iter = str.begin();
>>
>> std::advance(iter);
>> printf("%c\n", *iter);
>>
>> std::prev(iter);
>> printf("%c\n", *iter);
>>
>> iter--;
>> printf("%c\n", *iter);
>>
>> Output is
>> e
>> e
>> t
>>
>> Any ideas why it doesn't work?
>
> Because unlike std::advance, std::prev doesn't modify its argument, it
> returns the new iterator instead.
>
> http://en.cppreference.com/w/cpp/iterator/prev

So, for completeness, you probably want to do this instead:

iter = std::prev(iter);

or std::advance(iter, -1)
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Problem using std::prev on ustring iterator

2016-03-19 Thread Jonathan Wakely
On 18 March 2016 at 17:57, jeremy.harmon wrote:
> Hello,
>
> When I try to use std::prev on a ustring const_iterator nothing
> happens, operator-- works fine.
>
> Glib::ustring str = "test";
> Glib::ustring::iterator iter = str.begin();
>
> std::advance(iter);
> printf("%c\n", *iter);
>
> std::prev(iter);
> printf("%c\n", *iter);
>
> iter--;
> printf("%c\n", *iter);
>
> Output is
> e
> e
> t
>
> Any ideas why it doesn't work?

Because unlike std::advance, std::prev doesn't modify its argument, it
returns the new iterator instead.

http://en.cppreference.com/w/cpp/iterator/prev
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Replace Gtk::manage() with std::unique_ptr<>?

2016-02-08 Thread Jonathan Wakely

On 08/02/16 10:18 +1300, Ian Martin wrote:
As you've said, using unique_pointer mandates a design with only one 
access point to the controlled object,


That's not true.

std::unique_ptr mandates one *owner* of the object, but that doesn't
prevent you accessing it through any number of non-owning pointers.

The only caveat is that you must ensure that the object is still valid
for as long as you use the non-owning pointers, i.e. there is still an
owner keeping it alive. Otherwise your non-owning pointers become
dangling and accessing the expired object is undefined behaviour.

If you cannot guarantee that the owning pointer outlives the
non-owning pointers then unique_ptr is not the right solution. Instead
you can use std::shared_ptr as the owner (even if you only have a
single owner) because that allows you to use std::weak_ptr as the
non-owning observer. The benefit of std::weak_ptr is that you can (in
fact, must) check whether there is still a shared_ptr that owns the
object before you access it, so you can never access an expired object
through a weak_ptr, instead you get an empty shared_ptr or an
exception. That means there can be no dangling pointers that have
undefined behaviour when dereferenced.


___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Replace Gtk::manage() with std::unique_ptr<>?

2016-02-08 Thread Jonathan Wakely

On 08/02/16 13:19 +0100, Murray Cumming wrote:

On Mon, 2016-02-08 at 11:56 +, Jonathan Wakely wrote:
[snip]

A cleaner API would operate in terms of rvalues returned from
functions, and passed straight into other functions, avoiding
std::move entirely.

[snip]

Do you mean like this?

 window.add(create_button("something"));

That's already possible by just taking a std::unique_ptr<> by value.


Yes, but it doesn't give you a non-owning pointer which can be used to
do other things to the button (either before or after adding it to the
window) which is what the thread was about. Your proposed patch in
Bugzilla has lots of TODO comments for use-after-move (which is
undefined behaviour and crashes).

What I'm saying is that those user-after-move need to be fixed by one
of:

(1) taking a raw pointer before transferring ownership by moving the
   unique_ptr, which you suggested at
   https://mail.gnome.org/archives/gtkmm-list/2016-February/msg00011.html

(2) have the "add" functions return a raw pointer, as Diether suggested
   at
   https://mail.gnome.org/archives/gtkmm-list/2016-February/msg00014.html

(3) add a helper that extracts a non-owning raw pointer as the rvalue
  passes by, as I suggested in
  https://mail.gnome.org/archives/gtkmm-list/2016-February/msg00018.html


You said (1) "doesn't seem much better" than use-after-move, which I
disagree with. It's infinitely better because it is not undefined and
doesn't crash :-) But it's not ideal because it doesn't allow rvalues
to be passed straight from factory functions to sinks. You must create
an intermediate local variable, extract a raw pointer, then use
std::move to cast back to an rvalue.

Options (2) and (3) both allow rvalues to be passed straight from
factories to sinks, but allow a non-owning pointer to be obtained at
the same time.



However, I wouldn't want to enforce that if it forced people to write
code like this, without being able to break it up into separate lines:

 window.add(
   create_frame_with_children(
 create_label("something"),
 create_button("some button")));


It doesn't enforce anything. You always have the option of storing the
returned objects in local variables and moving them in, if that's what
you prefer.

But if you prefer *not* to do that, so that you don't need to use
std::move() and don't leave any empty unique_ptr objects lying around,
then only options (2) and (3) allow you to do that.

Option (1) enforces intermediate local variables.

Options (2) and (3) allow the programmer to choose.

___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Replace Gtk::manage() with std::unique_ptr<>?

2016-02-08 Thread Jonathan Wakely

On 08/02/16 00:08 +0100, Murray Cumming wrote:

On Sun, 2016-02-07 at 22:51 +0100, Dr. Diether Knof wrote:

Hello,

I think, to use std::unique_ptr and std::move instead of Gtk::manage
is a good
idea, but it is more difficult to use:

>   auto widget = std::make_unique("some button");
OK
>   notebook.append_page(std::move(widget), "something");
OK, but widget does no longer point to the botton, compare with the
example at
http://en.cppreference.com/w/cpp/utility/move
>   notebook.child_property_tab_expand(*widget) = true;
Should lead to a segmentation fault.

[snip]

Yes, it does, and that's the issue here.

(I've heard various discussions of what the C++ standard specifies
about how valid or defined the moved-from object is, but I would indeed
prefer to avoid any use after move.)


It's not complicated, but it's often explained badly, or by people who
don't know the rules.

For any type defined in the C++ standard library (unless it specifies
stronger guarantees) a moved-from object is in a *valid* but
*unspecified* state.  Valid but unspecified means it still maintains
its invariants, but you can't assume anything more about its state. So
you can't know if it's safe to call functions that have preconditions
unless you first check that the preconditions are met.

e.g. a moved-from std::string may or may not be empty, so doing s[4]
may or may not be safe. However you can use any member functions that
have no preconditions, so you can call s.size() to discover the
string's state, and then it's safe to use s[4] if size() > 4.

Some types offer stronger guarantees and std::unique_ptr is one of
them. Obviously a type that models unique ownership has to stop owning
its pointer after it transfers to another object, so std::unique_ptr
is guaranteed to be null after it is moved from. So dereferencing it
is undefined behaviour (typically resulting in a segfault).

(In general the guarantees above are only true for types defined in
the Standard Library. For non-standard types it is good style, and
highly recommended, to follow at least the "valid but unspecified"
guarantee for moved-from objects, with stronger guarantees for types
like smart pointers where that makes sense. However in general class
authors can define whatever semantics they want for their own types
after they are moved from. So if a class author says that after being
moved from her type can only be destroyed or assigned a new value,
that's OK.)


[snip]

So, in order to create a widget, move it into a container and use it
afterwards, we have to create two pointers (the unique-pointer and a
normal
pointer):

>   auto widget = std::make_unique("some button");
OK
>   Gtk::Widget* widget_to_expand = *widget;
Wrong, right is:
Gtk::Widget* widget_to_expand = widget.get();
>   notebook.append_page(std::move(widget), "something";
OK


This is a fairly typical idiom: get a raw (non-owning) pointer that
will remain valid after ownership is transferred from the (owning)
unique_ptr to something else.

The owning pointer is unique, but the non-owning pointer is not, you
can have as many non-owning observer pointers as you want.

The downside of this approach is that you can't do:

 extern std::unique_ptr button_factory(const char*);

 notebook.append_page( button_factory("some button"), "something" );

i.e. you can't pass an rvalue straight to a function taking a
std::unique_ptr, because you don't get a chance to take the raw
pointer from it. So you need to create an lvalue, get a raw pointer,
then cast back to an rvalue using std::move:

 auto button = button_factory("some button");
 Button* raw = button.get();
 notebook.append_page( std::move(button), "something" );
 raw->blahblah();

This is more verbose and more error-prone because 'button' is left
hanging around, containing null, tempting people to dereference it and
get a segfault.


Another idea is to change the add-methods to return a pointer to the
object
added. So the code can be written as (for clearity with Gtk::Button*
instead
of auto):
Gtk::Button* button =
container.add_unique(std::make_unique("a
button"));

For this, Container::add_unique() must be a (simple?) template, so it
returns
the exact type for the pointer (Gtk::Button*) and not Gtk::Widget*:
template
X* Container::add_unique(std::unique_ptr(X) widget)
{
  X* p = widget.get();
  this->add(std::move(widget));
  return p;
}
virtual void Container::add(std::unique_ptr widget);

[snip]


This is nicer, because you can pass an rvalue straight in, but still
get a raw pointer:

 Button* button = c.add_unique( button_factory("some button") );

This style avoids needing any explicit std::move() to cast the
std::unique_ptr back to an rvalue, and doesn't leave any null object
hanging around.


Yes, I've considered this, but I'm still hoping for something nicer.


The suggestion above looks fine to me. Certainly better than a
segfault :-)


I think I'd be content with needing a call to a getter method after a
std::move(). I think that would make 

Re: Replace Gtk::manage() with std::unique_ptr<>?

2016-02-08 Thread Jonathan Wakely

On 08/02/16 15:40 +0100, Murray Cumming wrote:

On Mon, 2016-02-08 at 12:40 +, Jonathan Wakely wrote:
[snip]

You said (1) "doesn't seem much better" than use-after-move, which I
disagree with. It's infinitely better because it is not undefined and
doesn't crash :-)


Of course. I don't want code that looks wrong and crashes. Sorry for
the confusion caused by my choice of words.


 But it's not ideal because it doesn't allow rvalues
to be passed straight from factory functions to sinks. You must
create
an intermediate local variable, extract a raw pointer, then use
std::move to cast back to an rvalue.

Options (2) and (3) both allow rvalues to be passed straight from
factories to sinks, but allow a non-owning pointer to be obtained at
the same time.

[snip]

Ah, now I see your point. Thanks.

I do find your suggested API awkward (I've renamed add_unique() to add()):


I agree, it's not ideal, so I hope there's still a better solution
waiting to be found.


 Button* b = nullptr; //I don't like this being even momentarily uninitialized. 
murrayc.
  c.add(pass_and_observe(button_factory("some button"), b));
  b->blahblah();

However, it's just one pass_and_observe() template that works on top of the 
simple
add(unique_ptr<>) overloads. People could use it they wanted to, or use a 
get_child()
method if they preferred, trying to leave an explicit std::move() as late as 
possible
so they didn't need to. I hope we can improve the occasional API that makes this
difficult currently.


By the way, would you want people to use this even without a factory method? 
For instance:

 Button* b = nullptr; //I don't like this being even momentarily uninitialized. 
murrayc.


Yep, fair enough :-)


  c.add(pass_and_observe(std::make_unique("some button"), b));
  b->blahblah();


Could do. I guess it depends on how much gtkmm devs (which I'm not!)
would want to avoid using std::move() and leaving null lvalues around.
That's not necessarily a bad thing, but is a potential source of
use-after-move bugs. I've seen it suggested that any explicit use of
std::move is a code smell because of those potential bugs (I'm not
sure I entirely agree, but can see their point).

___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Replace Gtk::manage() with std::unique_ptr<>?

2016-02-08 Thread Jonathan Wakely

On 08/02/16 15:56 +0100, Murray Cumming wrote:

On Mon, 2016-02-08 at 15:44 +0100, Krzesimir Nowak wrote:

Just a minor hint here - Button* b {}; should do the trick and it is
not that lot more of typing.


Thanks. Whether we should now use curly brackets for "uniform
initialization" wherever possible is a whole other question we should
discuss eventually. It looks odd to me, but I accept that that's no
reason not to like it. I expect to get used to it.


Personally I continue using "= nullptr" for pointers. Uniform init is
great for generic code as it works for anything default constructible,
and great in many other situations, but to initialize a pointer to
null I think "= nullptr" is as clear and explicit as you can get.

But I'm not a gtkmm dev or even a gtkmm user, and YMMV :-)

___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list