std::declval<T>() and array types

373 views
Skip to first unread message

Jim Porter

unread,
Feb 6, 2015, 4:27:39 PM2/6/15
to std-dis...@isocpp.org
Because of the implementation of std::declval<T>(), it's impossible to
find the correct overload for std::begin() if T is an array type. I know
C arrays disobey many of the usual properties of types in C++, but this
seems like something that should Just Work.

template<typename T>
struct iterated {
using type = decltype(*std::begin(std::declval<T>()));
};

using X = typename iterated<std::vector<int>>::type; // OK
using Y = typename iterated<int[2]>::type; // FAILS

If you want to play around with the code, you can go here:
<http://ideone.com/Jtn7YF>.

Is this something worthy of a fix to the standard? I don't think we
should expect users to write template specializations for arrays just to
make something like this work.

Of course, if there's a better way to create a trait like this, I'd be
happy to hear about it.

- Jim

Howard Hinnant

unread,
Feb 6, 2015, 4:50:06 PM2/6/15
to std-dis...@isocpp.org
It works for me if you feed an lvalue to std::begin:

#include <iostream>
#include <vector>
#include <iterator>
#include "type_name.h"

template<typename T>
struct iterated {
using type = decltype(*std::begin(std::declval<T&>()));
};

int
main()
{
using X = typename iterated<std::vector<int>>::type; // OK
std::cout << type_name<X>() << '\n';
using Y = typename iterated<int[2]>::type; // ok
std::cout << type_name<Y>() << '\n';
}

int&
int&

Howard

Jim Porter

unread,
Feb 6, 2015, 4:57:14 PM2/6/15
to std-dis...@isocpp.org
On 2/6/2015 3:50 PM, Howard Hinnant wrote:
> It works for me if you feed an lvalue to std::begin:

Hm, yeah, an lvalue would fix this. I guess this is just another case of
C arrays being weird. I do really wish some of the warts with C arrays
(like this) could be smoothed over, but I'm not sure there's a lot of
motivation to do so...

- Jim

David Krauss

unread,
Feb 6, 2015, 10:06:50 PM2/6/15
to std-dis...@isocpp.org

> On 2015–02–07, at 5:56 AM, Jim Porter <jvp...@g.rit.edu> wrote:
>
> On 2/6/2015 3:50 PM, Howard Hinnant wrote:
>> It works for me if you feed an lvalue to std::begin:
>
> Hm, yeah, an lvalue would fix this. I guess this is just another case of C arrays being weird.

You should typically use reference types with declval and when forming call expressions in decltype. The “default” is to emulate a prvalue, which behaves like an xvalue (rvalue reference), and that’s surprising. You seldom pass an rvalue to begin.

David Krauss

unread,
Feb 6, 2015, 10:11:24 PM2/6/15
to std-dis...@isocpp.org

On 2015–02–07, at 11:06 AM, David Krauss <pot...@gmail.com> wrote:

when forming call expressions in decltype.

Oh, that’s redundant. What I meant to mention is the weird std::result_of function signatures composed of a functor plus argument types. The functor type shouldn’t be a non-reference unless that’s you’re describing a prvalue.
Reply all
Reply to author
Forward
0 new messages