'Why does typename std::iterator_traits<ForwardIt>::value_type work but not decltype(*ForwardIt())

Why does this work ...

#include <iterator>

template<std::forward_iterator ForwardIt>
    requires std::integral<typename std::iterator_traits<ForwardIt>::value_type>
void radix_sort( ForwardIt begin, ForwardIt end )
{
    // ...
}

template
void radix_sort( int *, int * );

... but not this ...

#include <iterator>

template<std::forward_iterator ForwardIt>
    requires std::integral<decltype(*ForwardIt())>
void radix_sort( ForwardIt begin, ForwardIt end )
{
    // ...
}

template
void radix_sort( int *, int * );

ForwardIt has a default-constructor in my case (maybe std::forward_iterator<> does check this anyway).

I like the second solution because it looks more readable for me.



Solution 1:[1]

@StoryTeller was right. This code works:

#include <iterator>
#include <type_traits>

template<std::forward_iterator ForwardIt>
    requires std::is_integral_v<std::remove_cvref_t<decltype(*ForwardIt())>>
void radix_sort( ForwardIt begin, ForwardIt end )
{
    // ...
}


template
void radix_sort( int *, int * );

But then it becomes longer than ...

requires std::integral<std::iter_value_t<ForwardIt>>

... so the "proper" solution isn't preferrable over the above.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1