Topic: Avoiding code duplication with const / non-const


Author: tmlen <timlenertz@gmail.com>
Date: Wed, 18 Mar 2015 14:41:23 -0700 (PDT)
Raw View
------=_Part_803_599048434.1426714883138
Content-Type: multipart/alternative;
 boundary="----=_Part_804_2110976634.1426714883138"

------=_Part_804_2110976634.1426714883138
Content-Type: text/plain; charset=UTF-8

Container classes like std::vector  often provide pairs of member functions
with almost the same functionality, one const and one non-const. In some
cases these functions are trivial (ex. std::array::operator[]) but they can
also be more complex functions, like std::map::equal_range.
There is often no "good" way to implement such functions:

(1) Manually writing two functions with (almost) identical code can be
difficult to maintain if the code/algorithm is large:
class int_set {
private:
    int* arr_;
    std::size_t size_;

public:
    int& find(int value) {
        auto end = arr_ + size_;
        for(auto it = arr_; it != end; ++it)
            if(*it == value) return *it;
        throw std::invalid_argument("Not in set.");
    }

    const int& find(int value) const {
        auto end = arr_ + size_;
        for(auto it = arr_; it != end; ++it)
            if(*it == value) return *it;
        throw std::invalid_argument("Not in set.");
    }
};


(2) Avoiding the problem by defining a different interface:
class int_set {
private:
    int* arr_;
    std::size_t size_;

public:
    std::ptrdiff_t find(int value) const {
        auto end = arr_ + size_;
        for(auto it = arr_; it != end; ++it)
            if(*it == value) return (it - arr_);
        throw std::invalid_argument("Not in set.");
    }

    int& operator[](std::ptrdiff_t i) { return arr_[i]; }
    const int& operator[](std::ptrdiff_t i) const { return arr_[i]; }
};



(3) Another way is to make the calls forward to a templated member
function, which gets instantiated in a const and non-const version. But
this produces hard-to-read code and needs more complex constructs such as
std::conditional :
class int_set {
private:
    int* arr_;
    std::size_t size_;

    template<typename Int_set>
    static auto find_(Int_set& self, int value)
    -> std::conditional<std::is_const<Int_set>::value, const int&, int&> {
        auto end = self.arr_ + self.size_;
        for(auto it = self.arr_; it != end; ++it)
            if(*it == value) return *it;
        throw std::invalid_argument("Not in set.");
    }

public:
    int& find(int value) {
        return find_(*this, value);
    }

    const int& find(int value) const {
        return find_(*this, value);
    }
};

(4) Implementing one variant and using const_cast for the other. May result
in undefined behavior, and not always possible (for example when std::vector<int*>
would need to become std::vector<const int*>).  But it has the advantage
that the same binary code is not generated twice (similar to generics vs
templates).

class int_set {
private:
    int* arr_;
    std::size_t size_;

public:
    int& find(int value) {
        const int& result = static_cast<const int_set&>(*this).find(value);
        return const_cast<int&>(result);
    }

    const int& find(int value) const {
        auto end = arr_ + size_;
        for(auto it = arr_; it != end; ++it)
            if(*it == value) return *it;
        throw std::invalid_argument("Not in set.");
    }
};




The underlying problem seems to be that *container classes *which own their
elements need to enforce const-correctness, i.e. assure that when the
caller has const access to the container, it can not get non-const access
to its elements. (as for the STL containers, and automatically for public
data members.)

*View* classes on the other hand always give const or non-const access,
regardless if access to the view class is const. So there may be two
variants of the view class, such as iterator and const_iterator. Or it
depends on the constness of a template argument, like std::unique_ptr.
(There can be a similar code duplication problem here.)

--

Maybe it would be useful to have an automated way to generate const and
non-const member functions. For example using a new keyword autoconst (probably
a bad choice since it is similar to auto const):

class int_set {
private:
    int* arr_;
    std::size_t size_;
public:
    autoconst int& find(int value) autoconst {
        auto end = arr_ + size_;
        for(auto it = arr_; it != end; ++it)
            if(*it == value) return *it;
        throw std::invalid_argument("Not in set.");
    }
};


The semantics of autoconst would be:

- If a member function is marked autoconst the compiler will generate two
functions, from the one autoconst declaration and definition. One const and
one non-const.
- autoconst can be used to qualify types in the declaration (return type
and parameters), and types within the definition. In an autoconst function, autoconst
T evaluates to T in the non-const version and to const T in the const
version.

Even when the functions share the same code, their implementation may still
be different: For example the with code
auto begin_it = begin();
in an autoconst function, it can become an iterator in the non-const
version, and a const_iterator in the const version. Because begin() is
still manually defined in the two variants.

It may also be possible to define criteria for when the binary code
generated from compiling the autoconst function versions will be exactly
the same for both versions, so that the compiler can merge them as an
optimization.

--

---
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/.

------=_Part_804_2110976634.1426714883138
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Container classes like <font face=3D"courier new, monospac=
e">std::vector</font>&nbsp;&nbsp;often provide pairs of member functions wi=
th almost the same functionality, one const and one non-const. In some case=
s these functions are trivial (ex. <font face=3D"courier new, monospace">st=
d::array::operator[]</font>) but they can also be more complex functions, l=
ike <font face=3D"courier new, monospace">std::map::equal_range</font><font=
 face=3D"arial, sans-serif">.</font><div><font face=3D"arial, sans-serif">T=
here is often no "good" way to implement such functions:</font></div><div><=
font face=3D"arial, sans-serif"><br></font></div><div><font face=3D"arial, =
sans-serif">(1) Manually writing two functions with (almost) identical code=
 can be difficult to maintain if the code/algorithm is large:</font></div><=
div><div class=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187, 187=
); font-family: arial, sans-serif; background-color: rgb(250, 250, 250); wo=
rd-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettypr=
int"><font color=3D"#660066"><span class=3D"styled-by-prettify" style=3D"co=
lor: rgb(0, 0, 136);">class</span><span class=3D"styled-by-prettify" style=
=3D"color: rgb(0, 0, 0);">&nbsp;int_set&nbsp;</span><span class=3D"styled-b=
y-prettify" style=3D"color: rgb(102, 102, 0);">{</span><span class=3D"style=
d-by-prettify" style=3D"color: rgb(0, 0, 0);"><br></span><span class=3D"sty=
led-by-prettify" style=3D"color: rgb(0, 0, 136);">private</span><span class=
=3D"styled-by-prettify" style=3D"color: rgb(102, 102, 0);">:</span><span cl=
ass=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 0);"><br>&nbsp; &nbsp;=
&nbsp;</span><span class=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 1=
36);">int</span><span class=3D"styled-by-prettify" style=3D"color: rgb(102,=
 102, 0);">*</span><span class=3D"styled-by-prettify" style=3D"color: rgb(0=
, 0, 0);">&nbsp;arr_</span><span class=3D"styled-by-prettify" style=3D"colo=
r: rgb(102, 102, 0);">;</span><span class=3D"styled-by-prettify" style=3D"c=
olor: rgb(0, 0, 0);"><br>&nbsp; &nbsp; std</span><span class=3D"styled-by-p=
rettify" style=3D"color: rgb(102, 102, 0);">::</span><span class=3D"styled-=
by-prettify" style=3D"color: rgb(0, 0, 0);">size_t size_</span><span class=
=3D"styled-by-prettify" style=3D"color: rgb(102, 102, 0);">;<br></span><spa=
n class=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 0);"><br></span></=
font></div><div class=3D"subprettyprint"><font color=3D"#660066"><span clas=
s=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 0);">public:<br>&nbsp; &=
nbsp; int&amp; find(int value) {<br></span></font><span style=3D"color: rgb=
(0, 0, 0);">&nbsp; &nbsp; &nbsp; &nbsp; auto end =3D arr_ + size_;</span><b=
r style=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);">&nbsp=
; &nbsp; &nbsp; &nbsp; for(auto it =3D arr_; it !=3D end; ++it)</span><br s=
tyle=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);">&nbsp; &=
nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(*it =3D=3D value) return *it;</span><b=
r style=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);">&nbsp=
; &nbsp; &nbsp; &nbsp; throw std::invalid_argument("Not in set.");</span><b=
r style=3D"color: rgb(0, 0, 0);"><font color=3D"#660066"><span class=3D"sty=
led-by-prettify" style=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; }<br><br></sp=
an></font><span style=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; const int&amp;=
 find(int value) const {</span><br style=3D"color: rgb(0, 0, 0);"><span sty=
le=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; &nbsp; &nbsp; auto end =3D arr_ +=
 size_;</span><br style=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(=
0, 0, 0);">&nbsp; &nbsp; &nbsp; &nbsp; for(auto it =3D arr_; it !=3D end; +=
+it)</span><br style=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(0, =
0, 0);">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(*it =3D=3D value) retu=
rn *it;</span><br style=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(=
0, 0, 0);">&nbsp; &nbsp; &nbsp; &nbsp; throw std::invalid_argument("Not in =
set.");</span><br style=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(=
0, 0, 0);">&nbsp; &nbsp; }</span><font color=3D"#660066"><span class=3D"sty=
led-by-prettify" style=3D"color: rgb(0, 0, 0);"><br></span><span class=3D"s=
tyled-by-prettify" style=3D"color: rgb(102, 102, 0);">};</span></font></div=
></code></div><br style=3D"font-family: arial, sans-serif;"></div><div><fon=
t face=3D"arial, sans-serif"><br></font></div><div><font face=3D"arial, san=
s-serif">(2) Avoiding the problem by defining a different interface:</font>=
</div><div><font face=3D"arial, sans-serif"><div class=3D"prettyprint" styl=
e=3D"background-color: rgb(250, 250, 250); border: 1px solid rgb(187, 187, =
187); word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"sub=
prettyprint"><div class=3D"subprettyprint"><font color=3D"#660066"><span cl=
ass=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 136);">class</span><sp=
an class=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 0);">&nbsp;int_se=
t&nbsp;</span><span class=3D"styled-by-prettify" style=3D"color: rgb(102, 1=
02, 0);">{</span><span class=3D"styled-by-prettify" style=3D"color: rgb(0, =
0, 0);"><br></span><span class=3D"styled-by-prettify" style=3D"color: rgb(0=
, 0, 136);">private</span><span class=3D"styled-by-prettify" style=3D"color=
: rgb(102, 102, 0);">:</span><span class=3D"styled-by-prettify" style=3D"co=
lor: rgb(0, 0, 0);"><br>&nbsp; &nbsp;&nbsp;</span><span class=3D"styled-by-=
prettify" style=3D"color: rgb(0, 0, 136);">int</span><span class=3D"styled-=
by-prettify" style=3D"color: rgb(102, 102, 0);">*</span><span class=3D"styl=
ed-by-prettify" style=3D"color: rgb(0, 0, 0);">&nbsp;arr_</span><span class=
=3D"styled-by-prettify" style=3D"color: rgb(102, 102, 0);">;</span><span cl=
ass=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 0);"><br>&nbsp; &nbsp;=
 std</span><span class=3D"styled-by-prettify" style=3D"color: rgb(102, 102,=
 0);">::</span><span class=3D"styled-by-prettify" style=3D"color: rgb(0, 0,=
 0);">size_t size_</span><span class=3D"styled-by-prettify" style=3D"color:=
 rgb(102, 102, 0);">;<br></span><span class=3D"styled-by-prettify" style=3D=
"color: rgb(0, 0, 0);"><br></span></font></div><div class=3D"subprettyprint=
"><font color=3D"#660066"><span class=3D"styled-by-prettify" style=3D"color=
: rgb(0, 0, 0);">public:<br>&nbsp; &nbsp; std::ptrdiff_t find(int value) co=
nst {<br></span></font><span style=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; &=
nbsp; &nbsp; auto end =3D arr_ + size_;</span><br style=3D"color: rgb(0, 0,=
 0);"><span style=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; &nbsp; &nbsp; for(=
auto it =3D arr_; it !=3D end; ++it)</span><br style=3D"color: rgb(0, 0, 0)=
;"><span style=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; if(*it =3D=3D value) return (it - arr_);</span><br style=3D"color: r=
gb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; &nbsp; &nb=
sp; throw std::invalid_argument("Not in set.");</span><br style=3D"color: r=
gb(0, 0, 0);"><font color=3D"#660066"><span class=3D"styled-by-prettify" st=
yle=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; }<br><br>&nbsp; &nbsp; int&amp; =
operator[](std::ptrdiff_t i) { return arr_[i]; }<br>&nbsp; &nbsp;</span></f=
ont><span style=3D"color: rgb(0, 0, 0);">&nbsp;const int&amp; operator[](st=
d::ptrdiff_t i) const { return arr_[i]; }</span><font color=3D"#660066"><sp=
an class=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 0);"><br></span><=
/font><span style=3D"color: rgb(102, 102, 0); font-family: arial, sans-seri=
f;">};</span><font color=3D"#660066"><span class=3D"styled-by-prettify" sty=
le=3D"color: rgb(0, 0, 0);"><br></span></font></div></div></code></div><br>=
</font></div><div><font face=3D"arial, sans-serif"><br></font></div><div><f=
ont face=3D"arial, sans-serif"><br></font></div><div><font face=3D"arial, s=
ans-serif">(3) Another way is to make the calls forward to a templated memb=
er function, which gets instantiated in a const and non-const version. But =
this produces hard-to-read code and needs more complex constructs such as <=
/font><font face=3D"courier new, monospace">std::conditional</font><font fa=
ce=3D"arial, sans-serif">&nbsp;:</font></div><div><font face=3D"arial, sans=
-serif"><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250,=
 250); border: 1px solid rgb(187, 187, 187); word-wrap: break-word;"><code =
class=3D"prettyprint"><div class=3D"subprettyprint"><font color=3D"#660066"=
><span style=3D"color: #008;" class=3D"styled-by-prettify">class</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> int_set </span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">private</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">:</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br>&nbsp; &nbsp; </span><span style=3D"color: #0=
08;" class=3D"styled-by-prettify">int</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">*</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> arr_</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br>&nbsp; &nbsp; std</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify">size_t size_</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br></span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></=
span></font></div><div class=3D"subprettyprint"><font color=3D"#660066"><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify">&nbsp; &nbsp; </span=
><span style=3D"color: #008;" class=3D"styled-by-prettify">template</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">typename</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #606;" class=3D"styled-by-prettify">Int_set</span><span style=3D"color:=
 #660;" class=3D"styled-by-prettify">&gt;</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"><br>&nbsp; &nbsp; </span><span style=3D"colo=
r: #008;" class=3D"styled-by-prettify">static</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> find_(Int_set&amp; self, int value)<br>&nbsp; &nbsp; -=
&gt; std::conditional&lt;std::is_const&lt;Int_set&gt;::value, const int&amp=
;, int&amp;&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; auto end =3D self.arr_ + s=
elf.size_;<br>&nbsp; &nbsp; &nbsp; &nbsp; for(auto it =3D self.arr_; it !=
=3D end; ++it)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(*it =3D=3D v=
alue) return *it;<br>&nbsp; &nbsp; &nbsp; &nbsp; throw std::invalid_argumen=
t("Not in set.");<br>&nbsp; &nbsp; }<br><br>public:<br>&nbsp; &nbsp; int&am=
p; find(int value) {<br>&nbsp; &nbsp; &nbsp; &nbsp; return find_(*this, val=
ue);<br>&nbsp; &nbsp; }<br><br></span></font><span style=3D"color: rgb(0, 0=
, 0);">&nbsp; &nbsp; const int&amp; find(int value) const {</span><br style=
=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);"></span><span=
 style=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; &nbsp; &nbsp; return find_(*t=
his, value);</span><br style=3D"color: rgb(0, 0, 0);"><span style=3D"color:=
 rgb(0, 0, 0);">&nbsp; &nbsp; }</span><font color=3D"#660066"><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">};</span></font></div></code></div=
><br>(4) Implementing one variant and using </font><font face=3D"courier ne=
w, monospace">const_cast</font><font face=3D"arial, sans-serif">&nbsp;for t=
he other. May result in undefined behavior, and not always possible (for ex=
ample when&nbsp;</font><span style=3D"font-family: 'courier new', monospace=
;">std::vector&lt;int*&gt; </span><font face=3D"arial, sans-serif">would ne=
ed to become</font><span style=3D"font-family: 'courier new', monospace;">&=
nbsp;</span><span style=3D"font-family: 'courier new', monospace;">std::vec=
tor&lt;const int*&gt;</span><span style=3D"font-family: arial, sans-serif;"=
>). &nbsp;But it has the advantage that the same binary code is not generat=
ed twice (similar to generics vs templates).</span></div><div><br></div><di=
v><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250);=
 border: 1px solid rgb(187, 187, 187); word-wrap: break-word;"><code class=
=3D"prettyprint"><div class=3D"subprettyprint"><div class=3D"subprettyprint=
"><font color=3D"#660066"><span class=3D"styled-by-prettify" style=3D"color=
: rgb(0, 0, 136);">class</span><span class=3D"styled-by-prettify" style=3D"=
color: rgb(0, 0, 0);">&nbsp;int_set&nbsp;</span><span class=3D"styled-by-pr=
ettify" style=3D"color: rgb(102, 102, 0);">{</span><span class=3D"styled-by=
-prettify" style=3D"color: rgb(0, 0, 0);"><br></span><span class=3D"styled-=
by-prettify" style=3D"color: rgb(0, 0, 136);">private</span><span class=3D"=
styled-by-prettify" style=3D"color: rgb(102, 102, 0);">:</span><span class=
=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 0);"><br>&nbsp; &nbsp;&nb=
sp;</span><span class=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 136)=
;">int</span><span class=3D"styled-by-prettify" style=3D"color: rgb(102, 10=
2, 0);">*</span><span class=3D"styled-by-prettify" style=3D"color: rgb(0, 0=
, 0);">&nbsp;arr_</span><span class=3D"styled-by-prettify" style=3D"color: =
rgb(102, 102, 0);">;</span><span class=3D"styled-by-prettify" style=3D"colo=
r: rgb(0, 0, 0);"><br>&nbsp; &nbsp; std</span><span class=3D"styled-by-pret=
tify" style=3D"color: rgb(102, 102, 0);">::</span><span class=3D"styled-by-=
prettify" style=3D"color: rgb(0, 0, 0);">size_t size_</span><span class=3D"=
styled-by-prettify" style=3D"color: rgb(102, 102, 0);">;<br></span><span cl=
ass=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 0);"><br></span></font=
></div><div class=3D"subprettyprint"><font color=3D"#660066"><span class=3D=
"styled-by-prettify" style=3D"color: rgb(0, 0, 0);">public:<br>&nbsp; &nbsp=
; int&amp; find(int value) {<br>&nbsp; &nbsp; &nbsp; &nbsp; const int&amp; =
result =3D static_cast&lt;const int_set&amp;&gt;(*this).find(value);<br>&nb=
sp; &nbsp; &nbsp; &nbsp; return const_cast&lt;int&amp;&gt;(result);<br></sp=
an></font><font color=3D"#660066"><span class=3D"styled-by-prettify" style=
=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; }<br><br></span></font><span style=
=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; const int&amp; find(int value) cons=
t {</span><br style=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0=
, 0);">&nbsp; &nbsp; &nbsp; &nbsp; auto end =3D arr_ + size_;</span><br sty=
le=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);">&nbsp; &nb=
sp; &nbsp; &nbsp; for(auto it =3D arr_; it !=3D end; ++it)</span><br style=
=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp=
; &nbsp; &nbsp; &nbsp; &nbsp; if(*it =3D=3D value) return *it;</span><br st=
yle=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);">&nbsp; &n=
bsp; &nbsp; &nbsp; throw std::invalid_argument("Not in set.");</span><br st=
yle=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);">&nbsp; &n=
bsp; }</span><font color=3D"#660066"><span class=3D"styled-by-prettify" sty=
le=3D"color: rgb(0, 0, 0);"><br></span><span class=3D"styled-by-prettify" s=
tyle=3D"color: rgb(102, 102, 0);">};</span></font></div><div class=3D"subpr=
ettyprint"><font color=3D"#660066"><span class=3D"styled-by-prettify" style=
=3D"color: rgb(102, 102, 0);"><br><br></span></font></div></div></code></di=
v><br><br></div><div>The underlying problem seems to be that <i>container c=
lasses </i>which own their elements need to enforce const-correctness, i.e.=
 assure that when the caller has const access to the container, it can not =
get non-const access to its elements. (as for the STL containers, and autom=
atically for public data members.)</div><div><br></div><div><i>View</i>&nbs=
p;classes on the other hand always give const or non-const access, regardle=
ss if access to the view class is const. So there may be two variants of th=
e view class, such as <font face=3D"courier new, monospace">iterator&nbsp;<=
/font>and <span style=3D"font-family: 'courier new', monospace;">const_iter=
ator</span>. Or it depends on the constness of a template argument, like <f=
ont face=3D"courier new, monospace">std::unique_ptr</font>. (There can be a=
 similar code duplication problem here.)</div><div><br></div><div>--</div><=
div><br></div><div>Maybe it would be useful to have an automated way to gen=
erate const and non-const member functions. For example using a new keyword=
&nbsp;<font face=3D"courier new, monospace">autoconst</font><font face=3D"a=
rial, sans-serif">&nbsp;(probably a bad choice since it is similar to </fon=
t><font face=3D"courier new, monospace">auto const</font><font face=3D"aria=
l, sans-serif">):</font></div><div><font face=3D"arial, sans-serif"><br></f=
ont></div><div><font face=3D"arial, sans-serif"><div class=3D"prettyprint" =
style=3D"background-color: rgb(250, 250, 250); border: 1px solid rgb(187, 1=
87, 187); word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D=
"subprettyprint"><div class=3D"subprettyprint"><font color=3D"#660066"><spa=
n class=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 136);">class</span=
><span class=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 0);">&nbsp;in=
t_set&nbsp;</span><span class=3D"styled-by-prettify" style=3D"color: rgb(10=
2, 102, 0);">{</span><span class=3D"styled-by-prettify" style=3D"color: rgb=
(0, 0, 0);"><br></span><span class=3D"styled-by-prettify" style=3D"color: r=
gb(0, 0, 136);">private</span><span class=3D"styled-by-prettify" style=3D"c=
olor: rgb(102, 102, 0);">:</span><span class=3D"styled-by-prettify" style=
=3D"color: rgb(0, 0, 0);"><br>&nbsp; &nbsp;&nbsp;</span><span class=3D"styl=
ed-by-prettify" style=3D"color: rgb(0, 0, 136);">int</span><span class=3D"s=
tyled-by-prettify" style=3D"color: rgb(102, 102, 0);">*</span><span class=
=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 0);">&nbsp;arr_</span><sp=
an class=3D"styled-by-prettify" style=3D"color: rgb(102, 102, 0);">;</span>=
<span class=3D"styled-by-prettify" style=3D"color: rgb(0, 0, 0);"><br>&nbsp=
; &nbsp; std</span><span class=3D"styled-by-prettify" style=3D"color: rgb(1=
02, 102, 0);">::</span><span class=3D"styled-by-prettify" style=3D"color: r=
gb(0, 0, 0);">size_t size_</span><span class=3D"styled-by-prettify" style=
=3D"color: rgb(102, 102, 0);">;</span><span class=3D"styled-by-prettify" st=
yle=3D"color: rgb(0, 0, 0);"><br></span></font></div><div class=3D"subprett=
yprint"><font color=3D"#660066"><span class=3D"styled-by-prettify" style=3D=
"color: rgb(0, 0, 0);">public:<br></span></font><span style=3D"color: rgb(0=
, 0, 0);">&nbsp; &nbsp; autoconst int&amp; find(int value) autoconst {</spa=
n><br style=3D"color: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);">&=
nbsp; &nbsp; &nbsp; &nbsp; auto end =3D arr_ + size_;</span><br style=3D"co=
lor: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; &nbs=
p; &nbsp; for(auto it =3D arr_; it !=3D end; ++it)</span><br style=3D"color=
: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; if(*it =3D=3D value) return *it;</span><br style=3D"co=
lor: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; &nbs=
p; &nbsp; throw std::invalid_argument("Not in set.");</span><br style=3D"co=
lor: rgb(0, 0, 0);"><span style=3D"color: rgb(0, 0, 0);">&nbsp; &nbsp; }</s=
pan><font color=3D"#660066"><span class=3D"styled-by-prettify" style=3D"col=
or: rgb(0, 0, 0);"><br></span><span class=3D"styled-by-prettify" style=3D"c=
olor: rgb(102, 102, 0);">};</span></font></div></div></code></div><br><br><=
/font></div><div><font face=3D"arial, sans-serif">The semantics of&nbsp;</f=
ont><span style=3D"font-family: 'courier new', monospace;">autoconst</span>=
<span style=3D"color: rgb(0, 0, 0); background-color: rgb(250, 250, 250);">=
<font face=3D"arial, sans-serif">&nbsp;would be:</font></span></div><div><s=
pan style=3D"color: rgb(0, 0, 0); background-color: rgb(250, 250, 250);"><f=
ont face=3D"arial, sans-serif"><br></font></span></div><div><span style=3D"=
color: rgb(0, 0, 0); background-color: rgb(250, 250, 250);"><font face=3D"a=
rial, sans-serif">- If a member function is marked&nbsp;</font></span><span=
 style=3D"font-family: 'courier new', monospace;">autoconst</span><font fac=
e=3D"arial, sans-serif">&nbsp;the compiler will generate two functions, fro=
m the one </font><font face=3D"courier new, monospace">autoconst</font><fon=
t face=3D"arial, sans-serif"> declaration and definition. One const and one=
 non-const.</font></div><div><font face=3D"arial, sans-serif">- </font><fon=
t face=3D"courier new, monospace">autoconst</font><font face=3D"arial, sans=
-serif"> can be used to qualify types in the declaration (return type and p=
arameters), and types within the definition. In an autoconst function,&nbsp=
;</font><span style=3D"font-family: 'courier new', monospace;">autoconst T&=
nbsp;</span><span style=3D"font-family: arial, sans-serif;">evaluates to </=
span><font face=3D"courier new, monospace">T</font><span style=3D"font-fami=
ly: arial, sans-serif;"> in the non-const version and to </span><font face=
=3D"courier new, monospace">const T</font><span style=3D"font-family: arial=
, sans-serif;"> in the const version.</span></div><div><span style=3D"font-=
family: arial, sans-serif;"><br></span></div><div><span style=3D"font-famil=
y: arial, sans-serif;">Even when the functions share the same code, their i=
mplementation may still be different: For example the with code&nbsp;<div c=
lass=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border:=
 1px solid rgb(187, 187, 187); word-wrap: break-word;"><code class=3D"prett=
yprint"><div class=3D"subprettyprint"><font color=3D"#660066">auto begin_it=
 =3D begin();</font></div></code></div></span></div><div><span style=3D"fon=
t-family: arial, sans-serif;">in an autoconst function, </span><font face=
=3D"courier new, monospace">it</font><span style=3D"font-family: arial, san=
s-serif;"> can become an </span><font face=3D"courier new, monospace">itera=
tor</font><span style=3D"font-family: arial, sans-serif;"> in the non-const=
 version, and a&nbsp;</span><font face=3D"courier new, monospace">const_ite=
rator</font><span style=3D"font-family: arial, sans-serif;"> in the const v=
ersion. Because </span><font face=3D"courier new, monospace">begin()</font>=
<font face=3D"arial, sans-serif">&nbsp;is still manually defined in the two=
 variants.</font></div><div><font face=3D"arial, sans-serif"><br></font></d=
iv><div><font face=3D"arial, sans-serif">It may also be possible to define =
criteria for when the binary code generated from compiling the </font><font=
 face=3D"courier new, monospace">autoconst</font><font face=3D"arial, sans-=
serif"> function versions will be exactly the same for both versions, so th=
at the compiler can merge them as an optimization.</font></div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_804_2110976634.1426714883138--
------=_Part_803_599048434.1426714883138--

.


Author: David Krauss <potswa@gmail.com>
Date: Thu, 19 Mar 2015 07:55:49 +0800
Raw View
--Apple-Mail=_C7C95EB6-4C21-41F7-BD11-B68E90B113AC
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8


> On 2015=E2=80=9303=E2=80=9319, at 5:41 AM, tmlen <timlenertz@gmail.com> w=
rote:
>=20
> Maybe it would be useful to have an automated way to generate const and n=
on-const member functions. For example using a new keyword autoconst (proba=
bly a bad choice since it is similar to auto const):

I have a proposal in the works that uses export(const) for this purpose. Th=
is notation also supports preserving value category with export(const &&) a=
nd export(&&), and marks the function result as being an owned property of =
the object.

Draft PDF: http://bit.ly/genlife

Separating that feature from the lifetime stuff, it would be nice to see au=
to(const), auto(const &&), and auto(&&) as well.

Also, it would be nice to substitute patterns in non-template function para=
meters. It opens the door to combinatorial explosion, but only if you put a=
 lot of patterns in a row. And the explosion has already really happened, w=
e just don=E2=80=99t have syntax (aside from macros) to deal with it elegan=
tly.

--=20

---=20
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 e=
mail 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-proposa=
ls/.

--Apple-Mail=_C7C95EB6-4C21-41F7-BD11-B68E90B113AC
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8

<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dutf-8"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-mode: s=
pace; -webkit-line-break: after-white-space;" class=3D""><br class=3D""><di=
v><blockquote type=3D"cite" class=3D""><div class=3D"">On 2015=E2=80=9303=
=E2=80=9319, at 5:41 AM, tmlen &lt;<a href=3D"mailto:timlenertz@gmail.com" =
class=3D"">timlenertz@gmail.com</a>&gt; wrote:</div><br class=3D"Apple-inte=
rchange-newline"><div class=3D""><div dir=3D"ltr" class=3D""><div class=3D"=
">Maybe it would be useful to have an automated way to generate const and n=
on-const member functions. For example using a new keyword&nbsp;<font face=
=3D"courier new, monospace" class=3D"">autoconst</font><font face=3D"arial,=
 sans-serif" class=3D"">&nbsp;(probably a bad choice since it is similar to=
 </font><font face=3D"courier new, monospace" class=3D"">auto const</font><=
font face=3D"arial, sans-serif" class=3D"">):</font></div></div></div></blo=
ckquote><div><br class=3D""></div>I have a proposal in the works that uses =
<font face=3D"Courier" class=3D"">export(const)</font> for this purpose. Th=
is notation also supports preserving value category with <font face=3D"Cour=
ier" class=3D"">export(const &amp;&amp;)</font> and <font face=3D"Courier" =
class=3D"">export(&amp;&amp;)</font>, and marks the function result as bein=
g an owned property of the object.<br class=3D""></div><div><br class=3D"">=
</div><div>Draft PDF: <a href=3D"http://bit.ly/genlife" class=3D"">http://b=
it.ly/genlife</a></div><div class=3D""><br class=3D""></div>Separating that=
 feature from the lifetime stuff, it would be nice to see <font face=3D"Cou=
rier" class=3D"">auto(const)</font>, <font face=3D"Courier" class=3D"">auto=
(const &amp;&amp;)</font>, and <font face=3D"Courier" class=3D"">auto(&amp;=
&amp;)</font> as well.<div class=3D""><br class=3D""></div><div class=3D"">=
Also, it would be nice to substitute patterns in non-template function para=
meters. It opens the door to combinatorial explosion, but only if you put a=
 lot of patterns in a row. And the explosion has already really happened, w=
e just don=E2=80=99t have syntax (aside from macros) to deal with it elegan=
tly.</div></body></html>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

--Apple-Mail=_C7C95EB6-4C21-41F7-BD11-B68E90B113AC--

.