Customized decay semantics for "borrow/view" types?

53 views
Skip to first unread message

schreiber...@gmail.com

unread,
Apr 6, 2018, 3:08:40 PM4/6/18
to ISO C++ Standard - Discussion
Consider the following code:
    auto foo = []() {
        std
::vector<int> v(10);
       
// Do some work on 'v'
       
return v[0];
   
};

The return type of "foo()" is "int", despite the fact that "v[0]" is an expression of type "int&", because lambdas "decay" their returned expression to determine the return type. This is very well and good, since it avoids the silent appearances of dangling references.

Now consider the same code as above where "int" is replaced by "bool":
    auto foo = []() {
        std
::vector<bool> v(10);
       
// Do some work on 'v'
       
return v[0];
   
};

One would expect the return type to be "bool". But it's not. In gcc, it's "std::_Bit_reference"; it's a dangling reference to the vector "v" that existed in the lambda. The reason why is that "std::vector<bool>::operator[]" returns a "view" on the vector's content, and returns it by value. The deduction rules for lambda functions are fine with that, and simply return that value to the enclosing scope without actually "decaying" this "view" into the "bool" value it was pointing to, as would be semantically expected, thereby creating a dangling reference.

First off, I know, "std::vector<bool>" is evil on many aspects. That's not the point I want to make here. I choose "std::vector<bool>" because it's the only type in the standard that I know suffers from this issue, but it's a problem that actually shows up in DSL (for scientific computing) where "operator[]" is used to return a "view object" on a data vector. That "view" object is supposed to behave externally like an actual data vector, but only hold references to some data in another vector. Like "int&" behaves like "int". I suspect in the near future a lot of similar issues will arise with "std::string_view" or "std::array_view".

My question is the following. Is there currently a way to influence the deduction rules (of the lambda, or more generally) and customize the "decay" semantics for some types (such as "std::_Bit_reference" or whatever "view" type I create) such that the above code would return a "bool" value, without having to modify the function "foo()" itself to make an explicit cast?

If not, could this be achieved by specifying that lambdas must use "std::decay", and allowing "std::decay" to be a customization point?

schreiber...@gmail.com

unread,
Apr 6, 2018, 4:30:24 PM4/6/18
to ISO C++ Standard - Discussion, schreiber...@gmail.com
On Friday, April 6, 2018 at 9:08:40 PM UTC+2, schreiber...@gmail.com wrote:
I choose "std::vector<bool>" because it's the only type in the standard that I know suffers from this issue

Actually "std::valarray" and "std::bitset" have this issue as well.

Tony V E

unread,
Apr 6, 2018, 5:23:58 PM4/6/18
to std-discussion


People talk of this as "overloading operator auto".  There's been lots of talk, but nothing has made it into the language yet.

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+unsubscribe@isocpp.org.
To post to this group, send email to std-dis...@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.



--
Be seeing you,
Tony

Richard Smith

unread,
Apr 6, 2018, 5:36:50 PM4/6/18
to std-dis...@isocpp.org
On 6 April 2018 at 14:23, Tony V E <tvan...@gmail.com> wrote:
People talk of this as "overloading operator auto".  There's been lots of talk, but nothing has made it into the language yet.

I wish we had a better name for this; operator auto already means something else.

Tony V E

unread,
Apr 6, 2018, 5:41:06 PM4/6/18
to std-discussion
On Fri, Apr 6, 2018 at 5:36 PM, Richard Smith <ric...@metafoo.co.uk> wrote:
On 6 April 2018 at 14:23, Tony V E <tvan...@gmail.com> wrote:
People talk of this as "overloading operator auto".  There's been lots of talk, but nothing has made it into the language yet.

I wish we had a better name for this; operator auto already means something else.

I wish that something else wasn't called/spelled operator auto :(

schreiber...@gmail.com

unread,
Apr 6, 2018, 7:23:22 PM4/6/18
to ISO C++ Standard - Discussion
Thank you for the pointer! After reading the different proposals, I find the "delegate" based approach (http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0352r0.pdf) to be most elegant... Hopefully it will make it through for C++20!
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussio...@isocpp.org.

To post to this group, send email to std-dis...@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.

schreiber...@gmail.com

unread,
Apr 7, 2018, 6:27:43 AM4/7/18
to ISO C++ Standard - Discussion, schreiber...@gmail.com
Well, looks like my search skills were rusty... This paper talks about the very issue I mention in the first post:
http://wg21.link/P0672

Language Lawyer

unread,
Apr 7, 2018, 6:39:16 AM4/7/18
to ISO C++ Standard - Discussion, schreiber...@gmail.com
пятница, 6 апреля 2018 г., 22:08:40 UTC+3 пользователь schreiber...@gmail.com написал:
Consider the following code:
    auto foo = []() {
        std
::vector<int> v(10);
       
// Do some work on 'v'
       
return v[0];
   
};

The return type of "foo()" is "int", despite the fact that "v[0]" is an expression of type "int&"

"v[0]" is an expression of type "int".

schreiber...@gmail.com

unread,
Apr 7, 2018, 7:52:00 AM4/7/18
to ISO C++ Standard - Discussion, schreiber...@gmail.com
I'm sorry, but no. "v[0]" returns a "std::vector<T>::reference", which is a "T&".
http://en.cppreference.com/w/cpp/container/vector/operator_at

#include <vector>
#include <iostream>

int main(int argc, char* argv[]) {
    std
::vector<int> v;
   
using T = decltype(v[0]);

    std
::cout << std::is_same<T,int>::value << std::endl;        // 0
    std
::cout << std::is_same<T,int&>::value << std::endl;       // 1
    std
::cout << std::is_same<T,int&&>::value << std::endl;      // 0
    std
::cout << std::is_same<T,const int&>::value << std::endl; // 0
    std
::cout << std::is_same<T,const int>::value << std::endl;  // 0

   
return 0;
}


Nicolas Lesser

unread,
Apr 7, 2018, 11:58:33 AM4/7/18
to std-dis...@isocpp.org, schreiber...@gmail.com
On Sat, Apr 7, 2018 at 1:52 PM, <schreiber...@gmail.com> wrote:
On Saturday, April 7, 2018 at 12:39:16 PM UTC+2, Language Lawyer wrote:
пятница, 6 апреля 2018 г., 22:08:40 UTC+3 пользователь schreiber...@gmail.com написал:
Consider the following code:
    auto foo = []() {
        std
::vector<int> v(10);
       
// Do some work on 'v'
       
return v[0];
   
};

The return type of "foo()" is "int", despite the fact that "v[0]" is an expression of type "int&"

"v[0]" is an expression of type "int".
I'm sorry, but no. "v[0]" returns a "std::vector<T>::reference", which is a "T&".

Language Lawyer probably refers to the fact that expressions of type reference to T are adjusted to just T immediately, see [expr.type]p1.
 

#include <vector>
#include <iostream>

int main(int argc, char* argv[]) {
    std
::vector<int> v;
   
using T = decltype(v[0]);

    std
::cout << std::is_same<T,int>::value << std::endl;        // 0
    std
::cout << std::is_same<T,int&>::value << std::endl;       // 1
    std
::cout << std::is_same<T,int&&>::value << std::endl;      // 0
    std
::cout << std::is_same<T,const int&>::value << std::endl; // 0
    std
::cout << std::is_same<T,const int>::value << std::endl;  // 0

   
return 0;
}


--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+unsubscribe@isocpp.org.

schreiber...@gmail.com

unread,
Apr 7, 2018, 12:52:30 PM4/7/18
to ISO C++ Standard - Discussion, schreiber...@gmail.com
On Saturday, April 7, 2018 at 5:58:33 PM UTC+2, Nicolas Lesser wrote:
On Sat, Apr 7, 2018 at 1:52 PM, <schreiber...@gmail.com> wrote:
On Saturday, April 7, 2018 at 12:39:16 PM UTC+2, Language Lawyer wrote:
пятница, 6 апреля 2018 г., 22:08:40 UTC+3 пользователь schreiber...@gmail.com написал:
Consider the following code:
    auto foo = []() {
        std
::vector<int> v(10);
       
// Do some work on 'v'
       
return v[0];
   
};

The return type of "foo()" is "int", despite the fact that "v[0]" is an expression of type "int&"

"v[0]" is an expression of type "int".
I'm sorry, but no. "v[0]" returns a "std::vector<T>::reference", which is a "T&".

Language Lawyer probably refers to the fact that expressions of type reference to T are adjusted to just T immediately, see [expr.type]p1.
I could not find [expr.type] in the C++17 working draft, I assume you meant [expr] point 5. Looks like bikeshedding on the exact meaning of "the type of an expression", which may be very relevant for a language lawyer, but pretty much irrelevant to me and this discussion.

Nicolas Lesser

unread,
Apr 7, 2018, 1:24:54 PM4/7/18
to std-dis...@isocpp.org
On Sat, Apr 7, 2018 at 6:52 PM, <schreiber...@gmail.com> wrote:
I could not find [expr.type] in the C++17 working draft, I assume you meant [expr] point 5. Looks like bikeshedding on the exact meaning of "the type of an expression", which may be very relevant for a language lawyer, but pretty much irrelevant to me and this discussion.

Yes that's the one, I'm on the standard draft from http://eel.is/c++draft/, which has already been updated lots of times since C++17 was finished :). I completely agree that this is irrelevant to your discussion though.

Here's the timeline of p0352 in case you're interested. You might want to contact the authors, because I think they abandoned it:
- Oulu, Finland (2016): Postponed
- Issaquah, WA (2016): Reviewed with clear majority strongly in favor to encourage work in that direction; to be reviewed again in Kona
- Kona, HI (2017): Postponed
- never seen again...

schreiber...@gmail.com

unread,
Apr 8, 2018, 6:28:03 AM4/8/18
to ISO C++ Standard - Discussion
On Saturday, April 7, 2018 at 7:24:54 PM UTC+2, Nicolas Lesser wrote:
On Sat, Apr 7, 2018 at 6:52 PM, <schreiber...@gmail.com> wrote:
I could not find [expr.type] in the C++17 working draft, I assume you meant [expr] point 5. Looks like bikeshedding on the exact meaning of "the type of an expression", which may be very relevant for a language lawyer, but pretty much irrelevant to me and this discussion.

Yes that's the one, I'm on the standard draft from http://eel.is/c++draft/, which has already been updated lots of times since C++17 was finished :). I completely agree that this is irrelevant to your discussion though.
Thanks! I didn't know about this website. Much more convenient than a 1.5k page PDF!
 
Here's the timeline of p0352 in case you're interested. You might want to contact the authors, because I think they abandoned it:
- Oulu, Finland (2016): Postponed
- Issaquah, WA (2016): Reviewed with clear majority strongly in favor to encourage work in that direction; to be reviewed again in Kona
- Kona, HI (2017): Postponed
- never seen again...
Thank you very much for the summary. I actually contacted the authors of P0672 (proposing only for "using auto") since this is more directly related to the issue I'm having.
Reply all
Reply to author
Forward
0 new messages