220 5481 <CALQmNFhDCxL1fm6Dg7Rb=pK4PcXHSd9+syLo7zhxEJy=HpyYAQ@mail.gmail.com> article
Path: news.gmane.org!not-for-mail
From: Sean Middleditch <sean@middleditch.us>
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: flag types
Date: Mon, 22 Jul 2013 00:26:36 -0700
Lines: 174
Approved: news@gmane.org
Message-ID: <CALQmNFhDCxL1fm6Dg7Rb=pK4PcXHSd9+syLo7zhxEJy=HpyYAQ@mail.gmail.com>
References: <6333a3d3-4fdb-4295-ab86-a83184a20c47@isocpp.org>
	<CANh-dX=_CtcWrHor65ZKb=evVPyOfL7vHe-R7Lt+-mAEmW4h2Q@mail.gmail.com>
	<CAOfiQqkY9kre2Nn1eJF=R1eVBBBEQHAZJWTORTVY5inK+ihznA@mail.gmail.com>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: plane.gmane.org
Mime-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1
X-Trace: ger.gmane.org 1374478002 7318 80.91.229.3 (22 Jul 2013 07:26:42 GMT)
X-Complaints-To: usenet@ger.gmane.org
NNTP-Posting-Date: Mon, 22 Jul 2013 07:26:42 +0000 (UTC)
To: std-proposals@isocpp.org
Original-X-From: std-proposals+bncBCDODCNR2QPRBLV5WOHQKGQEPV75ONI@isocpp.org Mon Jul 22 09:26:45 2013
Return-path: <std-proposals+bncBCDODCNR2QPRBLV5WOHQKGQEPV75ONI@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-qc0-f199.google.com ([209.85.216.199])
	by plane.gmane.org with esmtp (Exim 4.69)
	(envelope-from <std-proposals+bncBCDODCNR2QPRBLV5WOHQKGQEPV75ONI@isocpp.org>)
	id 1V1AW1-0003Qn-73
	for gclcip-std-proposals@m.gmane.org; Mon, 22 Jul 2013 09:26:41 +0200
Original-Received: by mail-qc0-f199.google.com with SMTP id a1sf8184216qcx.10
        for <gclcip-std-proposals@m.gmane.org>; Mon, 22 Jul 2013 00:26:40 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20120113;
        h=x-beenthere:mime-version:sender:in-reply-to:references:date
         :message-id:subject:from:to:x-original-sender
         :x-original-authentication-results:reply-to:precedence:mailing-list
         :list-id:x-google-group-id:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe:content-type;
        bh=NlInoTrTdXqGPrh713aVnOtbo96HGuQ/zTmEgpaZntw=;
        b=pDGJ464FEFQ8LFhSJOA4K0goP9mf71hJjR3u1Ri2jb9codUHTOqmIlpTMrAA0xNEVN
         7aIm7g0QPl4NxPiKD3miQANAdIxLZAmNeUdVVCjyItmxj+25elkCyIE0C6zCupSO73uv
         XwKDEJ6DtsAZwblqs/H4R7pIaw505sfV4GTGssT17cRvkyZs2jWQ6BoKnYz+Uo+DbjD1
         HlpEeDzqvGs/sAYXRWrVtZAlhsPvMWeMzW2U9DkWcGzze5EZ9HaWfZ8M9l9joBoTxEuE
         rCknO95yQRQ8EKaAEsxKp2H8vDQcdEySvbIE612n3+9TcWqrYcES8jonSg1GThndlqVO
         mecw==
X-Received: by 10.236.123.70 with SMTP id u46mr14737307yhh.20.1374478000378;
        Mon, 22 Jul 2013 00:26:40 -0700 (PDT)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.49.106.195 with SMTP id gw3ls2464651qeb.64.gmail; Mon, 22 Jul
 2013 00:26:38 -0700 (PDT)
X-Received: by 10.52.232.165 with SMTP id tp5mr7450929vdc.11.1374477997997;
        Mon, 22 Jul 2013 00:26:37 -0700 (PDT)
Original-Received: from mail-vb0-x230.google.com (mail-vb0-x230.google.com [2607:f8b0:400c:c02::230])
        by mx.google.com with ESMTPS id dq2si312573vdc.50.2013.07.22.00.26.36
        for <std-proposals@isocpp.org>
        (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128);
        Mon, 22 Jul 2013 00:26:36 -0700 (PDT)
Received-SPF: pass (google.com: domain of sean.middleditch@gmail.com designates 2607:f8b0:400c:c02::230 as permitted sender) client-ip=2607:f8b0:400c:c02::230;
Original-Received: by mail-vb0-f48.google.com with SMTP id w15so4566884vbf.35
        for <std-proposals@isocpp.org>; Mon, 22 Jul 2013 00:26:36 -0700 (PDT)
X-Received: by 10.220.203.197 with SMTP id fj5mr9269163vcb.60.1374477996865;
 Mon, 22 Jul 2013 00:26:36 -0700 (PDT)
Original-Sender: sean.middleditch@gmail.com
Original-Received: by 10.59.12.202 with HTTP; Mon, 22 Jul 2013 00:26:36 -0700 (PDT)
In-Reply-To: <CAOfiQqkY9kre2Nn1eJF=R1eVBBBEQHAZJWTORTVY5inK+ihznA@mail.gmail.com>
X-Original-Sender: sean@middleditch.us
X-Original-Authentication-Results: mx.google.com;       spf=pass (google.com:
 domain of sean.middleditch@gmail.com designates 2607:f8b0:400c:c02::230 as
 permitted sender) smtp.mail=sean.middleditch@gmail.com;       dkim=pass header.i=@gmail.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Google-Group-Id: 399137483710
List-Post: <http://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <http://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <http://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <http://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <http://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:5481
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/5481>

QFlags represents the best you can do now, which is exactly what I was
getting at as a nasty workaround.  I already know how to handle flags
today; I'm not exactly new at this game. :)

** QFlags and its ilk is the problem I'd like to solve here, not the
solution. **  Macros, no proper scoping of values, doesn't use the new
C++11 enum classes, can't be used with forward-declared enums, the
problem list goes on.

Again, I'm all for library-only solutions.  QFlags ain't it.
std::bitset fails due to not using the type system at all (nothing
stops you from accidentally combining flags1::value with flags2::value
into the same bitset, and there's other issues involving how you'd
define "combined flag" constants in an obvious clean way).  Pasting
together operator overloads for every set of flags is repetitive and
error-pone.

If the answer is "suck it up and deal with it," fine, that's what we
do already... but should we have to post C++17?  Going to the ideal I
listed originally is probably a bit too much in terms of one-off
semantics, I agree, but surely there's a compromise we could discuss
involving much more minor (and useful elsewhere) tweaks enabling a
very clean and robust standard library solution, rather than "use
macros and throw away the type system" ?

If there were an easier way to define sets of operator overloads for
any enum, it could be a bit easier, maybe?  Going back to the "old
style" enums, and ignoring temporarily the problem of combined
constants, a template perhaps could be:

  namespace std {
    struct nullflag_t { };
    static constexpr nullflag_t nullflag;

    template <typename EnumType>
    // this inheritance is not allowed currently, of course; just a
strawman idea of how one could "inject"
    // enum names into a class's namespace, I don't think this is the
ideal syntax here
    class flag_set : public EnumType {
    public:
      typedef std::make_unsigned<typename
std::underlying_type<EnumType>::type>::type int_type;

      flag_set() = default;
      constexpr flag_set(const std::nullflag_t&) : _value(0) { }
      constexpr flag_set(EnumType value) : _value(1 << value) { }
      explicit constexpr flag_set(int_type value) : _value(value) { }

      explicit constexpr operator int_type() const { return int_type(_value); }

      friend constexpr flag_set operator|(flag_set lhs, flag_set rhs)
{ return flag_set(int_type(_value)|int_type(_value)); }
      // other relevant bitwise operators

    private:
    EnumType _value;
  };

This is very close to what is done today, plus all that macro nonsense
you see in things like QFlags to get around the lack of ability to
inject scopes.

Being able to inject the enum scope gives two things in this case.
First, it means that you don't have one type name meant for use of
values of a flag set and entirely different one for "constants" of the
value set.  Two, it means with some additional unpleasantness you
could also introduce "parallel" names for constant _combinations_ of
flags, albeit with some ugly syntax:

  enum class flags_values { first, second, third };
  struct flags : public std::flag_set<flags_values> {
    constexpr flag_set<flags_values> all = first|second|third;
  };

  // definition is awkward but not usage is super obvious
  auto foo = flags::all & ~flags::second; // decltype(foo) ===
std::flag_set<flags_values>, probably not a serious issue

It of course may be cleaner to just treat the base enum type as is
done today (the actual bit pattern and not a bit offset that must be
shifted) and just continue requiring the client user to remember to
use powers of two for unique bits.  I've seen people have trouble with
that in the past but I'm thinking binary literals will make it way
better, probably "good enough," for most developers and relatively
easy to teach.

Without at least that, you end up with something similar to this, if
avoiding macros:

  enum class flags { none = 0b0000, first = 0b0001, second = 0b0010,
third = 0b0100 };
  constexpr auto flags_all = std::flag_set<flags>(flags::first) |
flags::second | flags::third; // necessary cast of first element

  auto foo = flags::first; // just a plain enum class, not a flag set,
auto as "dragon typing"
  auto foo = std::flag_set<flags>(flags::first);

  auto bar = flags::all ^ flags::second; // oops, 'all' is not part of
the flags scope like every other value
  auto bar = flags_all ^ flags::second; // better remember where each
value lives!

  auto gaz = flags::first | flags::second; // oops, didn't define all
the operator overloads
  auto gaz = std::flag_set<flags>(flags::first) | flags::second; // *sigh*

  flags baz = 0; // oops, illegal conversion from int to enum class!
  flags baz = std::nullflag; // oops, illegal conversion to enum class!
  auto baz = flags::none; // not terrible, but have fun with templates
and be sure to consistently name the none value!

Clearly, the above is non-ideal.  QFlags' macros make it slightly less
error-prone in some ways, more so in others.

On Sun, Jul 21, 2013 at 10:24 PM, Richard Smith <richard@metafoo.co.uk> wrote:
> On Sun, Jul 21, 2013 at 9:19 PM, Jeffrey Yasskin <jyasskin@google.com>
> wrote:
>>
>> I think std::bitset<N> provides most of the functionality you want
>> here. You'd define a normal enum class with contiguous values, and
>> you'd use the bitset type for sets of such enums. With the
>> std::max_enumeration_value<type> you suggest, one could easily write
>> an enum_set<enum_t> which deduces the proper N for a bitset.
>
>
> Look at Qt's QFlags for a pre-rolled implementation of something similar:
> QFlags<enum_type> gives you a type-safe collection of flags, with a complete
> set of bitwise operations. The only missing piece is that you need to
> manually specify the values for your enumeration constants as powers of two:
>
> enum flag_values {
>   none = 0,
>   first = 0x1,
>   second = 0x2,
>   third = 0x4
> };
> using flags = QFlags<flag_values>;
>
> Given that you can solve nearly all of this problem in a library, adding a
> significant new core language feature to support it seems excessive to me.
>
> --
>
> ---
> You received this message because you are subscribed to a topic in the
> Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/a/isocpp.org/d/topic/std-proposals/1RPxJSJ_0z8/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>
>



-- 
Sean Middleditch
http://seanmiddleditch.com

-- 

--- 
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.



.
