Using concepts to define an arbitrarily-nested initializer_list constructor

Viewed 68

I am trying to create an initializer_list constructor for an n-dimensional array object. I started by defining the following type traits and concepts:

#include <initializer_list>
#include <type_traits>

template <typename T, typename U>
struct is_nested_initializer_list_of : std::false_type {};

template <typename T>
struct is_nested_initializer_list_of<T, std::initializer_list<T>>
    : std::true_type {};

template <typename T, typename U>
struct is_nested_initializer_list_of<T, std::initializer_list<U>>
    : is_nested_initializer_list_of<T, U> {};

template <typename T, typename U>
constexpr bool is_nested_initializer_list_of_v =
    is_nested_initializer_list_of<T, U>::value;

template <typename T, typename U>
concept nested_initializer_list_of = is_nested_initializer_list_of_v<T, U>;

template <typename T, typename U>
concept maybe_nested_initializer_list_of =
    std::is_same_v<T, U> || nested_initializer_list_of<T, U>;

If I have defined the concept correctly, nested_initializer_list_of<T, U> should be true if U is std::initializer_list<T>, std::initializer_list<std::initializer_list<T>>, etc., and false otherwise. maybe_nest_initializer_list<T, U> should also be true if U is T.

I then defined my class as follows:

template <typename T> class NDArray {
  std::vector<std::size_t> shape;
  std::vector<T> vector;

public:
  template <maybe_nested_initializer_list_of<T> U>
  constexpr NDArray(std::initializer_list<U> il) {
    ...
  }
};

Finally, I defined a quick main function to test the constructor:

int main() {
    NDArray<int> one{1, 2};
    NDArray<int> two{{1,2},{3,4}};
}

one compiles as expected, but two generates an error:

CLion inspection

No matching constructor for initialization of 'NDArray'

candidate constructor template not viable: requires single argument 'il', but 2 arguments were provided

candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided

candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 2 were provided

NMAKE error:

main.cpp: error C2440: 'initializing': cannot convert from 'initializer list' to 'ndarray::NDArray<int>'
test.cpp: note: No constructor could take the source type, or constructor overload resolution was ambiguous
NMAKE : fatal error U1077: 'C:\PROGRA~2\MICROS~2\2019\COMMUN~1\VC\Tools\MSVC\1429~1.301\bin\Hostx64\x64\cl.exe' : return code '0x2'
Stop.
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64\nmake.exe"' : return code '0x2'
Stop.
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64\nmake.exe"' : return code '0x2'
Stop.
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64\nmake.exe"' : return code '0x2'
Stop.
0 Answers
Related