I am trying to write mostly a reimplementation of std::array
. But, I am not very happy about the rules for aggregate initialization (and some other minor details) and thus do not want to use it.
Things I do not like with aggregate initilization:
- Having less than the necessary elements in the list, produces no error, this is particularly strange for aggregates of aggregates, e.g.
struct A { int x,y; }; std::array< A, 2 > arr{1,2,3}; // produces A[0].x = 1, A[0].y = 2, A[1].x = 1, A[1].y = 0
- private/deleted ctors are still callable by the user
class B { B() = delete; }; B{}; // no compile time error
What I have so far is the following:
#include <cstddef>
#include <type_traits>
#include <utility>
template< typename T, typename ... Ts >
inline constexpr bool areT_v = std::conjunction_v< std::is_same<T, Ts> ... >;
namespace ttt {
template< typename T, int N >
struct array
{
template< typename ... L >
array( L && ... lst ) : content{ std::forward< L >( lst ) ... } {
static_assert( sizeof...(L) == N || sizeof...(L)==0, "" );
static_assert( areT_v<T,L...>, "" );
}
array() = default; // not sure whether I need this one
using ContentType = typename std::conditional< N>=1 , T, char >::type;
ContentType content[ N>=1 ? N : 1];
/* member functions */
};
}
Actually I am quite happy with this implementation, apart from the following fact. Using
ttt::array
I have more ctor calls then when using std::array
. E.g.:
#include <array>
#include <iostream>
struct CLASS {
int x, y;
CLASS() {
std::cout << "def-ctor" << std::endl;
}
CLASS(int x_,int y_) : x(x_), y(y_) {
std::cout << "xy-ctor" << std::endl;
}
CLASS( CLASS const & other ) : x(other.x), y(other.y) {
std::cout << "copy-ctor" << std::endl;
}
};
int main() {
std::array< CLASS, 1 > stda{CLASS{1,2}}; // calls xy-ctor
ttt::array< CLASS, 1 > ttta{CLASS{1,2}}; // calls xy-ctor AND copy-ctor
}
This seems to be connected with the reason that std::array
is aggregate initialized (because it is an aggregate), but ttt::array
is not.
This leads me to the question, is the compiler allowed to do something here (omitting one ctor call), I am not allowed to do?
And, is there a way around this?
CLASS
and pass it tottt::array
constructor (which then has no choice but to copy or move it intocontent
); it can't bypass the constructor and write theCLASS
instance directly intocontent
array. I don't think you can avoid copying without makingttt::array
an aggregate (which would defeat the point). – Urianarray
. – Cineaste