집계 초기화를 위해 빈 기본 클래스 숨기기


9

다음 코드를 고려하십시오.

struct A
{
    // No data members
    //...
};

template<typename T, size_t N>
struct B : A
{
    T data[N];
}

이것이 당신이 B를 초기화하는 방법입니다 : B<int, 3> b = { {}, {1, 2, 3} }; 기본 클래스에 불필요한 빈 {}을 피하고 싶습니다. 이 Jarod42에 의해 제안 된 솔루션입니다 여기에 , 그러나, 그것은 요소의 기본 초기화 작동하지 않습니다는 : B<int, 3> b = {1, 2, 3};잘하지만 B<int, 3> b = {1};되지 않습니다 : b.data[1]b.data[2]0으로 초기화 기본적으로되지 않으며, 컴파일러 오류가 발생합니다. 기본 클래스를 생성에서 "숨길"수있는 방법이 있습니까 (또는 c ++ 20에있을 것입니까)?


2
왜 생성자를 추가하지 template<class... Ts> B(Ts... args) : data{args...} {}않습니까?
Evg

왜 댓글입니까? 작동하는 것 같습니다, lol
user7769147

이것은 당신이 그것을 사용하지 않을 이유가 있다고 생각한 명백한 해결책입니다. :)
EVG

너무 쉬운 xD였습니다. 답변으로
쓰면

답변:


6

가장 쉬운 해결책은 가변형 생성자를 추가하는 것입니다.

struct A { };

template<typename T, std::size_t N>
struct B : A {
    template<class... Ts, typename = std::enable_if_t<
        (std::is_convertible_v<Ts, T> && ...)>>
    B(Ts&&... args) : data{std::forward<Ts>(args)...} {}

    T data[N];
};

void foo() {
    B<int, 3> b1 = {1, 2, 3};
    B<int, 3> b2 = {1};
}

{...}초기화 목록에서보다 적은 수의 요소를 제공 N하면 배열의 나머지 요소 data는로 값이 초기화됩니다 T().


3
이것이 왜 집계 초기화와 다른지 알게되었습니다. B<Class, 5> b = {Class()}; Class집계 초기화를 사용하여 구성한 후에는 먼저 구성한 다음 이동하는 것으로 간주되는 경우 이동 Class이 발생하지 않습니다.
user7769147

@ user7769147, 좋은 지적입니다. std::tuple인수 를 가져 와서 객체를 제자리에 구성하는 데 사용할 수 있습니다 . 그러나 구문은 다소 번거로울 것입니다.
Evg

1
이 문제를 해결하는 솔루션을 무작위로 찾았습니다. 여러분의 가용성에 감사드립니다.
user7769147


4

여전히 생성자를 사용하면 다음과 같은 작업을 수행 할 수 있습니다.

template<typename T, size_t N>
struct B : A
{
public:
    constexpr B() : data{} {}

    template <typename ... Ts,
              std::enable_if_t<(sizeof...(Ts) != 0 && sizeof...(Ts) < N)
                               || !std::is_same_v<B, std::decay_t<T>>, int> = 0>
    constexpr B(T&& arg, Ts&&... args) : data{std::forward<T>(arg), std::forward<Ts>(args)...}
    {}

    T data[N];
};

데모

SFINAE는 주로 의사 복사 생성자를 만들지 않기 위해 수행됩니다 B(B&).

B<std::index_sequence<0, 1>, 42>;-) 를 지원하려면 추가 개인 태그가 필요합니다.


왜 필요한 ((void)Is, T())...가요? 단순히 생략하면 어떻게 되나요? 나머지 요소 T()는 기본적 으로 값으로 초기화되지 않습니까?
Evg

1
@Evg : 실제로 단순화되었습니다. 값을 초기화하는 대신 나머지 요소 만 기본 초기화하는 것이 두렵습니다 ...
Jarod42

2

나는 (어떻게 모르겠다) 완벽하게 작동하고 Evg의 답변에서 논의 한 문제를 해결하는 또 다른 해결책을 찾았습니다.

struct A {};

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

template<typename T, size_t N>
struct B : B_data<T, N>, A
{
    // ...
};

재미있는 해결책. 그러나 이제는 내부 를 사용 this->data하거나 using B_data::data;액세스해야합니다 . dataB
Evg
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.