I have a nested initializer_list ctor for creating 2D matrixes. Works great. But then I decided to add a simplified row vector matrix (n rows, 1 col) using a single initializer list. This is so I could create a row matrix like this: Matrix2D<int> x{1,2,3} instead of having to do this: Matrix2D<int> x{{1},{2},{3}}. Of course this required a separate ctor.
Everything worked including in constexpr with MSVC. But when checked using gcc and clang I'm getting ambiguous ctors. Seems pretty clear to me when the lists are nested and MSVC operates exactly as expected.
Here's the code:
// Comment out next line for only nested initializer_list ctor
#define INCLUDE_EXTRA_CTOR
#include <memory>
#include <numeric>
#include <initializer_list>
#include <exception>
#include <stdexcept>
#include <concepts>
using std::size_t;
template <typename T>
class Matrix2D {
T* const pv; // pointer to matrix contents
public:
const size_t cols;
const size_t rows;
// default ctor;
Matrix2D() noexcept : pv(nullptr), cols(0), rows(0) {}
// 2D List initialized ctor
Matrix2D(std::initializer_list<std::initializer_list<T>> list) :
pv((list.begin())->size() != 0 ? new T[list.size() * (list.begin())->size()] : nullptr),
cols(pv != nullptr ? (list.begin())->size() : 0),
rows(pv != nullptr ? list.size() : 0)
{
if (pv == nullptr)
return;
for (size_t row = 0; row < list.size(); row++)
{
if (cols != (list.begin() + row)->size())
throw std::runtime_error("number of columns in each row must be the same");
for (size_t col = 0; col < cols; col++)
pv[cols * row + col] = *((list.begin() + row)->begin() + col);
}
}
#ifdef INCLUDE_EXTRA_CTOR
// Row initialized ctor, rows=n, cols=1;
Matrix2D(std::initializer_list<T> list) :
pv(list.size() != 0 ? new T[list.size()] : nullptr),
cols(pv != nullptr ? 1 : 0),
rows(pv != nullptr ? list.size() : 0)
{
if (pv == nullptr)
return;
for (size_t row = 0; row < rows; row++)
{
pv[row] = *(list.begin() + row);
}
}
#endif
// dtor
~Matrix2D() { delete[] pv; }
};
int main()
{
// Tests of various possible null declarations
Matrix2D<int> x1{ }; // default
Matrix2D<int> x2{ {} }; // E0309, nested init list with 1 row, 0 cols, forced to 0 rows, 0 cols
Matrix2D<int> x3{ {},{} }; // E0309, nested init list with 2 rows, 0 cols, forced to 0 rows, 0 cols
// typical declaration
Matrix2D<int> x4{ {1,2},{3,4},{5,6} }; // nested init list with 3 rows, 2 cols
// standard row vector declaration
Matrix2D<int> x5{ {1},{2},{3} }; // E0309, init list with 3 rows, 1 col
#ifdef INCLUDE_EXTRA_CTOR
// row vector declaration
Matrix2D<int> x6{ 1,2,3 }; // init list with 3 rows, 1 col
#endif
}
E0309 is the MSVC intellisense ambiguous ctor error. However, compiles w/o error Why are gcc and clang deductions ambiguous? Is there a workaround?