also, for your example, do we really need following 2 member methods returning value of type "T&&" and "const T&&"?
auto operator*()
&& -> T&& { return
std::move(value); }
auto operator*() const&& -> T const&& {
return std::move(value); }
do you have code example to show the possible usage of these 2 methods?
Best Regards,
Jianping
and one more thing, for your example
template <typename T>
class optional {
union { char _; T value; };
bool has_value;
public:
auto operator*() & -> T& { return value; }
auto operator*() const& -> T const& { return value; }
auto operator*() && -> T&& { return std::move(value); }
auto operator*() const&& -> T const&& { return std::move(value); }
};do we really need to write "return std::move(value)" instead of simply "return value"? the new compiler should be able to handle it automatically for method with return type T&&.
Best Regards,
Jianping
On 12/15/2019 10:52 PM, jianping z wrote:
If we need both "const?" and "&&?" in a declaration/definition of a class method or a normal function, I think it's not difficult for compiler to handle them.
based on your sample, let's say compiler encounters "const?" first (vice versa)
compiler deal with "const?" first to generate two copies of the function from origin function
1. with const? removed (&&? not handled yet)
2. with const? replaced with const (&&? not handled yet)
then, as "&&?" is in both of these 2 generated functions, compiler can now deal with "&&?" to geneate two copies of the function from each of these 2 functions
1. with &&? replaced with &
2. with &&? replaced with &&
finally, 4 functions generated. it is still easy for compiler to generate, just take one more step to check the generated code to find if further process needed. how do you think?
Best Regards,
Jianping
On 12/15/2019 04:41 PM, Barry Revzin wrote:
On Fri, Dec 13, 2019 at 12:58 AM jianping z via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
// example-1b.hpp : much more concise, no more duplicated code (less
error prone)
class elements
{
int elem[10];
const? int& operator[](size_t n) const? { return elem[n]; }
const? int* data() const? { return elem; }
const? int* begin() const? { return elem; }
const? int* end() const? { return elem+10; }
}
I think this is pretty nice, and I appreciate the examples clearly illustrating how this is intended to work.
const or not const isn't the only axis we have to deal with though - we have one more: lvalue or rvalue. Today, optional::operator*() looks something like this (reduced for sanity):template <typename T>
class optional {
union { char _; T value; };
bool has_value;
public:
auto operator*() & -> T& { return value; }
auto operator*() const& -> T const& { return value; }
auto operator*() && -> T&& { return std::move(value); }
auto operator*() const&& -> T const&& { return std::move(value); }
};Now, with the const? feature, I could reduce these four overloads to two:
template <typename T>
class optional {
union { char _; T value; };
bool has_value;
public:
auto operator*() const?& -> T const?& { return value; }
auto operator*() const?&& -> T const?&& { return std::move(value); }
};
It'd really be nice to just have the one overload here. But with &/&&, it doesn't work as nicely since the question is no longer "to token or not to token", but rather a choice of two tokens. Maybe that's... fine and we could just say that &&? means & or && while const? means const or nothing. So that this spits out four functions for us:
template <typename T>
class optional {
union { char _; T value; };
bool has_value;
public:
auto operator*() const?&&? -> T const?&&? { return static_cast<T const?&&?>(value); }
};
Maybe this is too ugly, maybe we need a different way to pick references. But regardless one problem is that we'd need these two to unpack independently (that is, get the full cartesian product of {const, } x {&, &&}). But this goes against one of your examples where you illustrated:
template<typename T>
const? T& max(const? T& a, const? T& b)
as become two function templates (rather than four).
This 4x thing comes up a lot. std::get for std::tuple for instance might become:
template <size_t I, typename... Ts>auto get(tuple<Ts...> const?&&?) -> tuple_element_t<I, tuple<Ts...>>const?&&?;
Something to think about.
Barry