4

How do I use const qualifier with decltype for template-ed function ?

Current GCC rejects following :

template <typename It>
bool process(It first , It last )
{

  return  std::all_of( first, last, 
                       [](  const decltype(*first)& i )
                       //   ^^^^^ without const it works fine
                       { 
                            return i % 2 == 0; 
                       } 
                     ) ;
}

Is it legal/possible to use i as const reference inside the lambda ?

P0W
  • 46,614
  • 9
  • 72
  • 119
  • 1
    See http://stackoverflow.com/questions/7416251/using-decltype-to-cast-this-to-const. – Mihai8 Jun 08 '14 at 08:32
  • Looks like clang [accepts](http://coliru.stacked-crooked.com/a/95c2db6ee60006f0) it with `const` qualifier – P0W Jun 08 '14 at 08:32
  • 1
    @P0W Not quite as intended: it effectively ignores the `const` and gives `i` type `int&`. –  Jun 08 '14 at 08:45
  • 1
    [For some reason I found that a simple helper alias resolves the error.](http://coliru.stacked-crooked.com/a/75ade888e8aa724a) – David G Jun 08 '14 at 14:13

3 Answers3

5

const decltype(*first)& doesn't work because decltype(*first) is int&, but you expect it to be int. You can use std::remove_reference to work around that (although it doesn't really make the code clearer): const std::remove_reference<decltype(*first)>::type&

2

Just resolve to std::iterator_traits:

#include <algorithm>
#include <iterator>

template <typename It>
bool process(It first , It last )
{
    typedef typename std::iterator_traits<It>::value_type value_type;
    return std::all_of(first, last, []( const value_type& i ) {
        return i % 2 == 0;
    });
}

int main(void) {
    std::vector<int> v = { 0, 2, 4 };
    process(v.begin(), v.end());
}

Or without iterator_traits:

typedef typename std::decay<decltype(*first)>::type value_type;

Which leads to: A const qualifier is pointless for a reference and the const decltype(*first)&) is giving a false promise of having an immutable argument, which is actually mutable.

  • Thanks, yeah, this is the other way round, but it just happen that I ended up with that ugly way, and now I'm looking for _why_ that's failing – P0W Jun 08 '14 at 08:44
2

You could add_const :

template <typename It>
bool process(It first , It last )
{
  // std::cout << "Typeid :" << typeid( const decltype(*begin) &).name( ) << '\n' ;

  return  std::all_of( first, last, 
                       [](  typename add_const<decltype(*first)>::type &i )
                       { //          ^^^^^^^^^               
                            return i % 2 == 0; 
                       } 
                     ) ;
}
Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153