3

This program defines a simple container for an array of std::unique_ptr<unsigned int>.

#include <memory>
#include <array>
#include <type_traits>

template <unsigned int dim>
class container {
  template <std::size_t... I>
  container(std::array<unsigned int, dim> Ls, std::index_sequence<I...>) : container(std::get<I>(Ls)...) { }

public:
  const std::array<std::unique_ptr<unsigned int>, dim> data;

  template <typename... UInts, class = std::enable_if_t<(sizeof...(UInts) == dim) && (std::is_same_v<UInts, unsigned int> && ...)>>
  container(UInts... Ls) : data{ std::make_unique<unsigned int>(Ls)...} { }

  template <typename Indices = std::make_index_sequence<dim>>
  container(std::array<unsigned int, dim> Ls) : container(Ls, Indices{}) { }
};

int main()
{
  unsigned int x = 1;
  unsigned int y = 2;

  container<2> a({x,y});

  return 0;
}

The compilation with gcc 8.2.1 fails however, with the following error.

$ g++ -Wall -pedantic -std=c++17 -o test test.cpp

test.cpp: In function ‘int main()’:
test.cpp:25:23: error: call of overloaded ‘container(<brace-enclosed initializer list>)’ is ambiguous
   container<2> a({x,y});
                       ^
test.cpp:17:3: note: candidate: ‘container<dim>::container(std::array<unsigned int, dim>) [with Indices = std::integer_sequence<long unsigned int, 0, 1>; unsigned int dim = 2]’
   container(std::array<unsigned int, dim> Ls) : container(Ls, Indices{}) { }
   ^~~~~~~~~
test.cpp:6:7: note: candidate: ‘container<2>::container(const container<2>&)’ <deleted>
 class container {
       ^~~~~~~~~
test.cpp:6:7: note: candidate: ‘container<2>::container(container<2>&&)’ <deleted>
make: *** [Makefile:3: test] Error 1

Indeed, the copy constructor is deleted because of the presence of the array of std::unique_ptr (but still participates to the overload resolution).

Strangely, on gcc 7.3.0 the above code compiles with no errors or warnings.

Also, defining a simplified container, having a copyable array of unsigned int, as in the following program, no error occurs with both gcc 8.2.1 and gcc 7.3.0

#include <array>
#include <type_traits>

template <unsigned int dim>
class container_simple {
  template <std::size_t... I>
  container_simple(std::array<unsigned int, dim> Ls, std::index_sequence<I...>) : container_simple(std::get<I>(Ls)...) { }

public:
  const std::array<unsigned int, dim> data;

  template <typename... UInts, class = std::enable_if_t<(sizeof...(UInts) == dim) && (std::is_same_v<UInts, unsigned int> && ...)>>
  container_simple(UInts... Ls) : data{ Ls...} { }

  template <typename Indices = std::make_index_sequence<dim>>
  container_simple(std::array<unsigned int, dim> Ls) : container_simple(Ls, Indices{}) { }
};

int main()
{
  unsigned int x = 1;
  unsigned int y = 2;

  container_simple<2> a({x,y});

  return 0;
}

Is it a compiler bug? If not, where is the ambiguity?

francesco
  • 7,189
  • 7
  • 22
  • 49
  • `container<2> a{{x,y}};` also compiles fine of both clang/gcc [Demo](http://coliru.stacked-crooked.com/a/5c15dc1e51842cda) – Jarod42 Jun 26 '19 at 10:10
  • 1
    *"where is the ambiguity?"* `{x,y}` might be `std::array` or `container_simple(UInts... Ls)`. but I don't understand behavior of the different variations. – Jarod42 Jun 26 '19 at 10:18
  • Marking explicitly the copy constructor as deleted make gcc compile (but clang complains) [Demo](http://coliru.stacked-crooked.com/a/2d0656349be0dd7e) – Jarod42 Jun 26 '19 at 10:19

0 Answers0