Bug 71794 - Std::array as an incomplete type in nested name specifier.
Summary: Std::array as an incomplete type in nested name specifier.
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 6.1.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-07-07 10:55 UTC by Pawel Bednarski
Modified: 2016-07-07 12:25 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Code that won't compile on GCC. (227 bytes, text/x-csrc)
2016-07-07 10:55 UTC, Pawel Bednarski
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Pawel Bednarski 2016-07-07 10:55:04 UTC
Created attachment 38851 [details]
Code that won't compile on GCC.

In code attached: MyContainer type works perfectly fine. std::vector works fine as well.

Error message:
$ g++-6 -Wall -Wextra -Wpedantic --std=c++14  main.cpp 
main.cpp: In instantiation of ‘T foo() [with T = std::array<float, 4ul>]’:
main.cpp:39:31:   required from here
main.cpp:16:21: error: incomplete type ‘B<std::array<float, 4ul> >’ used in nested name specifier
     return B<T>::bar();
            ~~~~~~~~~^~
Comment 1 Jonathan Wakely 2016-07-07 11:42:52 UTC
This is nothing to do with libstdc++, the problem is that you've using int rather than std::size_t

using size_t = decltype(sizeof(0));

template<typename T, size_t N>
  struct array 
  {
     T data[N];
  };

template<typename T, int N>
struct MyContainer 
{
   T data[N];
};

template <typename T>
struct B;

template <typename T>
T foo()
{
    return B<T>::bar();
}

template <typename T, int N>
struct B<array<T, N>>
{
  static array<T, N> bar()
  {
      return array<T, N>();
  }
};

template <typename T, int N>
struct B<MyContainer<T, N>>
{
  static MyContainer<T, N> bar()
  {
      return MyContainer<T, N>();
  }
};

int main()
{
    foo<array<float, 4>>(); // incomplete type
    foo<MyContainer<float, 4>>();
}


foo<array<float, 4>> returns B<array<float, (size_t)4>> which doesn't match your partial specialization of B<array<float, (int)4>>

Clang accepts this, but G++ and EDG reject it for the same reason.
Comment 2 Jonathan Wakely 2016-07-07 11:43:44 UTC
If you fix your partial specialization it works with all compilers:

template <typename T, std::size_t N>  /* correct type */
struct B<std::array<T, N>>
{
  static std::array<T, N> bar()
  {
      return std::array<T, N>();
  }
};
Comment 3 Jonathan Wakely 2016-07-07 11:51:02 UTC
VC++ accepts it too, so it's two for and two against.

Reduced:

template<unsigned N> struct X { };

template<typename T> struct Y;

template<int N> struct Y<X<N>> { };

template<typename T> Y<T> f() { return {}; }

auto x = f< X<1> >();
Comment 4 Pawel Bednarski 2016-07-07 12:25:23 UTC
That's right Jonathan, thanks!