Topic: Function prolog proposal
Author: DeadMG <wolfeinstein@gmail.com>
Date: Fri, 18 Jan 2013 06:57:24 -0800 (PST)
Raw View
------=_Part_203_24760335.1358521044161
Content-Type: text/plain; charset=ISO-8859-1
I'm proposing a function prolog (working name). This is a section where you
can declare various qualifiers of the function you are defining. There are
three key benefits of this over the existing system:
Firstly, existing qualifiers can be computed, rather than having to be
declared. This can allow function re-use where it is currently impossible.
Secondly, new qualifiers don't require context-sensitive keywords, unlike
override and final- they can be regular identifiers. This reduces the cost
of adding new qualifiers in the future.
Thirdly, it can be used to improve the usability, in many ways, of SFINAE,
by providing dedicated language support.
The basic grammar of a function with a prolog goes along the lines of:
return-type identifier() prolog {
((qualified-name | const | volatile) = expression;)*
(return expression;) optional
} trailing-return-type-opt /* semicolon or body */
A simple example of the first is array access. If we provide a class which
has an array, and we wish to provide mutable or immutable access to that
array depending on whether *this is mutable or not, we currently have to
duplicate our functions. Some suggest using const_cast to avoid this.
However, with the proposed prolog, you can simply switch on whether or not
it is const. This means that, inside the body of the function prolog, *this
acts like a universal reference to the object.
class X {
int arr[5];
public:
/* ... */
auto operator[](std::size_t index) prolog {
const = std::is_const<decltype(*this)>::value;
} -> decltype(arr[index]) { return arr[index]; }
};
This is actually the default behaviour of the const qualifier, but any
user-defined constant expression is valid.
Here, we have written both const and non-const overloads in one go. For
other existing qualifiers , such as lvalue or rvalue, which are not
keywords, it should be simple to set special rules for some (potentially
qualified) names. As the name is any qualified name, there is no need for
additional context.
For the third, there are two main parts. The basic use is that the return
expression is used to indicate if the function body is valid, with
optionally a message to indicate why the function failed, if it did. For
example,
template<typename T> void f(T&& t)
prolog {
return { std::is_convertible<typename std::decay<T>::type, int>::value,
"T must be convertible to an int!" };
};
Here, there is no need to add dummy arguments, either to the template or
regular parameter list, and the SFINAE checking is clear and simple. In
addition, the implementation can report the diagnostic message provided if
there is a failure. This should aid users in understanding why the
implementation could not call a given function, or chose a specific
overload. The default return value is true, indicating that it is a valid
overload.
The second part is that, unless two prologs are identical, then each
defined function is considered to be a separate overload- even if the
template and non-template arguments are identical. Thus, the following are
considered two overloads, even though they previously would not be:
template<typename T> void f(T&& t)
prolog {
return { std::is_convertible<typename std::decay<T>::type, int>::value,
"T must be convertible to an int!" };
};
template<typename T> void f(T&& t)
prolog {
return { std::is_convertible<typename std::decay<T>::type,
float>::value, "T must be convertible to a float!" };
};
This should be a significant simplification on current schemes.
If the prolog returns false, then the function qualifiers are not
evaluated. This means that if they would yield a hard failure for some
arguments, if the prolog returns false for those arguments, there is only a
substitution failure instead.
Prologs are incompatible with existing qualifiers- the function author
chooses one or the other. For member functions, the default qualifiers are
the same as those on *this.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To post to this group, send email to std-proposals@isocpp.org.
To unsubscribe from this group, send email to std-proposals+unsubscribe@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_203_24760335.1358521044161
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div>I'm proposing a function prolog (working name). This is a section wher=
e you can declare various qualifiers of the function you are defining. Ther=
e are three key benefits of this over the existing system:</div><div><br></=
div><div>Firstly, existing qualifiers can be computed, rather than having t=
o be declared. This can allow function re-use where it is currently impossi=
ble.</div><div>Secondly, new qualifiers don't require context-sensitive key=
words, unlike override and final- they can be regular identifiers. This red=
uces the cost of adding new qualifiers in the future.</div><div>Thirdly, it=
can be used to improve the usability, in many ways, of SFINAE, by providin=
g dedicated language support.</div><div><br></div><div>The basic grammar of=
a function with a prolog goes along the lines of:</div><div><br></div><div=
>return-type identifier() prolog {</div><div> ((qualified-name=
| const | volatile) =3D expression;)*</div><div> (return expr=
ession;) optional</div><div>} trailing-return-type-opt /* semicolon or body=
*/</div><div><br></div><div>A simple example of the first is array access.=
If we provide a class which has an array, and we wish to provide mut=
able or immutable access to that array depending on whether *this is mutabl=
e or not, we currently have to duplicate our functions. Some suggest using =
const_cast to avoid this. However, with the proposed prolog, you can simply=
switch on whether or not it is const. This means that, inside the body of =
the function prolog, *this acts like a universal reference to the object.</=
div><div><br></div><div>class X {</div><div> int arr[5];</div>=
<div>public:</div><div> /* ... */</div><div><br></div><div>&nb=
sp; auto operator[](std::size_t index) prolog {</div><div> &nb=
sp; const =3D std::is_const<decltype(*this)>::value;</d=
iv><div> } -> decltype(arr[index]) { return arr[index]; }</=
div><div><br></div><div>};</div><div><br></div><div>This is actually the de=
fault behaviour of the const qualifier, but any user-defined constant expre=
ssion is valid.</div><div><br></div><div>Here, we have written both const a=
nd non-const overloads in one go. For other existing qualifiers , such as l=
value or rvalue, which are not keywords, it should be simple to set special=
rules for some (potentially qualified) names. As the name is any qualified=
name, there is no need for additional context.</div><div><br></div><div>Fo=
r the third, there are two main parts. The basic use is that the return exp=
ression is used to indicate if the function body is valid, with optionally =
a message to indicate why the function failed, if it did. For example,</div=
><div><br></div><div>template<typename T> void f(T&& t) =
</div><div>prolog {</div><div> return { std::is_convertible<=
;typename std::decay<T>::type, int>::value, "T must be convertible=
to an int!" };</div><div>};</div><div><br></div><div>Here, there is no nee=
d to add dummy arguments, either to the template or regular parameter list,=
and the SFINAE checking is clear and simple. In addition, the implementati=
on can report the diagnostic message provided if there is a failure. This s=
hould aid users in understanding why the implementation could not call a gi=
ven function, or chose a specific overload. The default return value is tru=
e, indicating that it is a valid overload.</div><div><br></div><div>The sec=
ond part is that, unless two prologs are identical, then each defined funct=
ion is considered to be a separate overload- even if the template and non-t=
emplate arguments are identical. Thus, the following are considered two ove=
rloads, even though they previously would not be:</div><div><br></div><div>=
template<typename T> void f(T&& t) </div><div>prolog {</=
div><div> return { std::is_convertible<typename std::decay&=
lt;T>::type, int>::value, "T must be convertible to an int!" };</div>=
<div>};</div><div><br></div><div>template<typename T> void f(T&&a=
mp; t) </div><div>prolog {</div><div> return { std::is_co=
nvertible<typename std::decay<T>::type, float>::value, "T must =
be convertible to a float!" };</div><div>};</div><div><br></div><div>This s=
hould be a significant simplification on current schemes.</div><div><br></d=
iv><div>If the prolog returns false, then the function qualifiers are not e=
valuated. This means that if they would yield a hard failure for some argum=
ents, if the prolog returns false for those arguments, there is only a subs=
titution failure instead.</div><div><br></div><div>Prologs are incompatible=
with existing qualifiers- the function author chooses one or the other. Fo=
r member functions, the default qualifiers are the same as those on *this.<=
/div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
To unsubscribe from this group, send email to std-proposals+unsubscribe@iso=
cpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_203_24760335.1358521044161--
.