Date: Mon, 29 Aug 2022 16:53:55 +0300
I personally think, this should be a minimal-syntax, non-overridable, unary
postscript operator that will work for both forward and move, much like
cast-to-T&& today
template <typename T> Dog(T&& name) : name(name&&) //< forward
{}
Name(string&& aName) : name(aName&&) //< move
{
cout << "Rvalue Name constructor." << endl;
}
If there is ambiguity with binary operator &&, the latter is chosen
template<class T>
void func(T&& a, int b) {
a&&-b //< ok, still operator&&(a,-b)
(a&&)-b //< ok, std::forward<T>(a) - b;
}
On Mon, Aug 29, 2022 at 2:31 AM Amar Saric via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> Perfect forwarding received a lot of attention initially when it was first
> added. By now, everybody should be clear on how it is used and what its
> purpose is. However, the syntax leaves something to be desired, as the
> forward template requires a parameter, which is actually not necessary, and
> frankly a bit ugly. This can be completely avoided by stripping the
> references and using a macro, as follows:
>
>
>
> #include <iostream>
>
> #include <string>
>
> #include <utility>
>
>
>
>
>
> namespace pf
>
> {
>
> template <typename T> struct check_if_ref
>
> {
>
> static_assert(std::is_reference<T>::value, "ref_forward needs a
> reference");
>
> typedef T type;
>
> };
>
> template <typename T> struct _remove_rvalue_reference
>
> {
>
> typedef T type;
>
> };
>
> template <typename T> struct _remove_rvalue_reference<T &&>
>
> {
>
> typedef T type;
>
> };
>
> template <typename T>
>
> using remove_rvalue_reference = typename _remove_rvalue_reference<T>::type;
>
> }
>
> #define ref_forward(p) (std::forward<pf::\
>
> remove_rvalue_reference<typename pf::\
>
> check_if_ref<decltype(p)>::type>>(p))
>
> #define ref_to_rvalue(p) (std::move(p))
>
>
>
>
>
> using std::cout;
>
> using std::endl;
>
> using std::string;
>
>
>
> class Name
>
> {
>
> public:
>
> Name(string& aName) : name(aName)
>
> {
>
> cout << "Lvalue Name constructor." << endl;
>
> }
>
>
>
> Name(string&& aName) : name(ref_to_rvalue(aName))
>
> {
>
> cout << "Rvalue Name constructor." << endl;
>
> }
>
>
>
> const string& getName() const { return name; }
>
>
>
> private:
>
> string name;
>
> };
>
>
>
> class Dog
>
> {
>
> public:
>
> template <typename T> Dog(T&& name) : name(ref_forward(name)) {}
>
> string getName() const { return name.getName(); }
>
>
>
> private:
>
> Name name;
>
> };
>
>
>
> void print(Dog& dog) { cout << "Dog is " << dog.getName() << endl; }
>
>
>
> int main()
>
> {
>
> cout << "Dog(string(\"Fido\"))) - rvalue argument:" << endl;
>
> Dog dog(string("Fido"));
>
> print(dog);
>
>
>
> cout << "Dog(\"Lassie\")) - rvalue const char* argument:" << endl;
>
> Dog another("Lassie");
>
> print(another);
>
>
>
> string var_name("Woofie");
>
> cout << "Dog(var_name) - lvalue argument:" << endl;
>
> Dog yetanother(var_name);
>
> print(yetanother);
>
>
>
> return 0;
>
> }
>
>
>
> Output:
>
>
>
> Dog(string("Fido"))) - rvalue argument:
>
> Rvalue Name constructor.
>
> Dog is Fido
>
> Dog("Lassie")) - rvalue const char* argument:
>
> Rvalue Name constructor.
>
> Dog is Lassie
>
> Dog(var_name) - lvalue argument:
>
> Lvalue Name constructor.
>
> Dog is Woofie
>
>
>
> Providing two macros similar to the ones above in a separate header would
> be nice to have in my opinion and, considering how may other features have
> been added over time, maybe others will feel the same. One could argue that
> this is just a matter of taste, but macros are used in other places as
> well. It is in a nutshell what I originally expected it to look like back
> in the day – what I personally find intuitive – and no means not cast in
> stone.
>
>
>
> Tell me what you think: Just a hack or is it worth it?
>
>
>
> Best,
>
>
>
> Amar
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
postscript operator that will work for both forward and move, much like
cast-to-T&& today
template <typename T> Dog(T&& name) : name(name&&) //< forward
{}
Name(string&& aName) : name(aName&&) //< move
{
cout << "Rvalue Name constructor." << endl;
}
If there is ambiguity with binary operator &&, the latter is chosen
template<class T>
void func(T&& a, int b) {
a&&-b //< ok, still operator&&(a,-b)
(a&&)-b //< ok, std::forward<T>(a) - b;
}
On Mon, Aug 29, 2022 at 2:31 AM Amar Saric via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> Perfect forwarding received a lot of attention initially when it was first
> added. By now, everybody should be clear on how it is used and what its
> purpose is. However, the syntax leaves something to be desired, as the
> forward template requires a parameter, which is actually not necessary, and
> frankly a bit ugly. This can be completely avoided by stripping the
> references and using a macro, as follows:
>
>
>
> #include <iostream>
>
> #include <string>
>
> #include <utility>
>
>
>
>
>
> namespace pf
>
> {
>
> template <typename T> struct check_if_ref
>
> {
>
> static_assert(std::is_reference<T>::value, "ref_forward needs a
> reference");
>
> typedef T type;
>
> };
>
> template <typename T> struct _remove_rvalue_reference
>
> {
>
> typedef T type;
>
> };
>
> template <typename T> struct _remove_rvalue_reference<T &&>
>
> {
>
> typedef T type;
>
> };
>
> template <typename T>
>
> using remove_rvalue_reference = typename _remove_rvalue_reference<T>::type;
>
> }
>
> #define ref_forward(p) (std::forward<pf::\
>
> remove_rvalue_reference<typename pf::\
>
> check_if_ref<decltype(p)>::type>>(p))
>
> #define ref_to_rvalue(p) (std::move(p))
>
>
>
>
>
> using std::cout;
>
> using std::endl;
>
> using std::string;
>
>
>
> class Name
>
> {
>
> public:
>
> Name(string& aName) : name(aName)
>
> {
>
> cout << "Lvalue Name constructor." << endl;
>
> }
>
>
>
> Name(string&& aName) : name(ref_to_rvalue(aName))
>
> {
>
> cout << "Rvalue Name constructor." << endl;
>
> }
>
>
>
> const string& getName() const { return name; }
>
>
>
> private:
>
> string name;
>
> };
>
>
>
> class Dog
>
> {
>
> public:
>
> template <typename T> Dog(T&& name) : name(ref_forward(name)) {}
>
> string getName() const { return name.getName(); }
>
>
>
> private:
>
> Name name;
>
> };
>
>
>
> void print(Dog& dog) { cout << "Dog is " << dog.getName() << endl; }
>
>
>
> int main()
>
> {
>
> cout << "Dog(string(\"Fido\"))) - rvalue argument:" << endl;
>
> Dog dog(string("Fido"));
>
> print(dog);
>
>
>
> cout << "Dog(\"Lassie\")) - rvalue const char* argument:" << endl;
>
> Dog another("Lassie");
>
> print(another);
>
>
>
> string var_name("Woofie");
>
> cout << "Dog(var_name) - lvalue argument:" << endl;
>
> Dog yetanother(var_name);
>
> print(yetanother);
>
>
>
> return 0;
>
> }
>
>
>
> Output:
>
>
>
> Dog(string("Fido"))) - rvalue argument:
>
> Rvalue Name constructor.
>
> Dog is Fido
>
> Dog("Lassie")) - rvalue const char* argument:
>
> Rvalue Name constructor.
>
> Dog is Lassie
>
> Dog(var_name) - lvalue argument:
>
> Lvalue Name constructor.
>
> Dog is Woofie
>
>
>
> Providing two macros similar to the ones above in a separate header would
> be nice to have in my opinion and, considering how may other features have
> been added over time, maybe others will feel the same. One could argue that
> this is just a matter of taste, but macros are used in other places as
> well. It is in a nutshell what I originally expected it to look like back
> in the day – what I personally find intuitive – and no means not cast in
> stone.
>
>
>
> Tell me what you think: Just a hack or is it worth it?
>
>
>
> Best,
>
>
>
> Amar
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2022-08-29 13:54:08