2

I have two versions of the what I'd expect to be the same function but gcc says version 1 is valid while version 2 gives a

expected a type, got 'std::remove_cv<_Iter>::type'

I don't quite understand this error, as I'd expect that the using statement required a type, and wouldn't automatically promote a 'std::remove_cv<_Iter>::type' to something else?

Can somebody explain whats going on here?

template<typename U,typename V> constexpr inline auto is_same_rcv() noexcept
{
    //version 1 works
    using u_underlying = std::remove_cv<U>::type;
    using v_underlying = std::remove_cv<V>::type;
    return std::is_same<u_underlying,v_underlying>::value;
}

and

template<typename U,typename V> constexpr inline auto is_same_rcv() noexcept
{
    //version 2 doesn't work
    using u_underlying = std::remove_cv<U>::type;
    return std::is_same<u_underlying,std::remove_cv<V>::type>::value;
}

Associated godbolt

Edit for fun, it looks like clang and gcc different on the interpretation of the using keyword (see https://godbolt.org/z/P9Pcn6)

Mikhail
  • 7,749
  • 11
  • 62
  • 136
  • TL;DR of the dupe, without `typename`, the language assumes `std::remove_cv::type` is a value. – NathanOliver Mar 19 '21 at 00:55
  • @NathanOliver Hmm, the dupe isn't very obvious. Where would typename go (its already in the signature) and why does `using` work but not when its part of the template... – Mikhail Mar 19 '21 at 00:58
  • The `typename` always prefixes the name, so `using u_underlying = typename std::remove_cv::type;` – NathanOliver Mar 19 '21 at 00:59
  • @NathanOliver Or rather should be `return std::is_same::type>::value;` – Mikhail Mar 19 '21 at 01:02
  • 1
    I reopened the question because it seems to be focused on the difference between the usage of `typename` in `using` statement and `return` statement. – songyuanyao Mar 19 '21 at 01:05
  • FYI, Clang gives a [very readable error](https://godbolt.org/z/7P889E) for this case. C++20 also allows elision of `typename` for the type aliases where a type is the only allowable thing that can be there. Offhand, I don't think it did the same for type arguments because it requires semantic analysis. (It seems Clang doesn't implement said change yet, so I added a couple `typename`s to focus on the relevant error message.) – chris Mar 19 '21 at 01:09
  • @chris Looks like clang and gcc differ on this one https://godbolt.org/z/P9Pcn6 ! Oh no! – Mikhail Mar 19 '21 at 01:15
  • Well, yes, I mentioned Clang appears not to support the change yet (C++20 is quite new after all). The point was rather that different compilers excel in different areas. Particularly when it comes to confusing errors, it's worth checking multiple compilers once the effort required to do so is sufficiently low. – chris Mar 19 '21 at 01:18

1 Answers1

5

You need to use the keyword typename to tell that the dependent names std::remove_cv<V>::type is a type.

return std::is_same<u_underlying, typename std::remove_cv<V>::type>::value;
//                                ^^^^^^^^

In the using statement typename is not needed again since C++20.

In some contexts, only type names can validly appear. In these contexts, a dependent qualified name is assumed to name a type and no typename is required:

  • ...

  • A qualified name that appears in type-id, where the smallest enclosing type-id is:

songyuanyao
  • 169,198
  • 16
  • 310
  • 405