아래 코드에서 두 개의 비 관련 구조체 B와 C가 포함 된 유니온 유사 클래스 S를 보여줍니다. 비 POD std :: string을 인스턴스화하는 방법을 보여줍니다 그것을 다시 삭제 한 다음 S를 S :: CC로 전환하고 num int를 설정하십시오.std :: initializer_list에서 유니온 같은 클래스 사용
#include <vector>
#include <string>
#include <iostream>
#include <memory>
struct B
{
B() {}
~B() {}
std::string str;
void Func1() {}
};
struct C
{
C() {}
~C() {}
int num;
void Func2() {}
};
struct S
{
S() { tag = CC; }
S(const S& s)
{
switch(s.tag)
{
case BB:
new (&b.str) std::string;
b.str = s.b.str;
break;
case CC:
c.num = s.c.num;
default:
break;
}
}
~S()
{
switch(tag)
{
case BB:
b.str.~basic_string<char>();
break;
case CC:
c.num = 0;
break;
default:
break;
}
}
enum { BB, CC } tag;
union
{
B b;
C c;
};
};
struct H
{
H(std::initializer_list<S> initializerList) : initListVect(initializerList) {}
std::vector<S> initListVect;
};
int main()
{
S s;
s.tag = S::BB;
new (&s.b.str) std::string; // docs say use new placement to create memory
s.b.str = "bbb";
s.b.str.~basic_string<char>(); // string usage in B ok
s.tag = S::CC;
s.c.num = 333; // int usage in C ok
H h { }; // what should the init list be if I wanted 3 list elements S::BB, S::CC, S::BB?
return 0;
}
그러나 내 목표는 std :: initializer_list에서 S를 사용하는 것입니다. h 형식을 초기화하기 위해 형식을 알아야합니다. 이 S :: BB, S :: CC, S :: BB로 h를 초기화하고 싶다면 인수는 무엇이되어야 하는가?
제 컴파일러는 VS2015입니다.
편집 : 이 게시물의 역사 : 내 게시는 std :: initializer_list에 컴파일 타임 - 추론 가능한 이기종 개체를 저장하는 질문에 대한 명확한 답이 필요합니다. 이 질문은 이전에 여러 번 묻어 왔으며 답변을 많이 시도했습니다 (Heterogeneous containers in C++ 참조). 가장 단순한 대답은 다형성 (polymorphism)을 사용하는 것이지만, 이것은 컴파일 타임 (템플릿)에서 타입을 정의 할 수있는 능력을 무시합니다. 게다가, 이종의 비 관련 객체들은 다형성으로 함께 그룹화되어 파생 된 많은 데이터 멤버들이 쓸모없고, 다운 스트림에서 사용 및 유지 관리 혼란을 초래한다는 것을 의미합니다. 다른 조언은 boost :: any 또는 boost :: variant를 사용하는 것이었지만 이것은 다형성과 같은 약점이 있으며 메시지 선언의 명확성을 줄입니다. 컨테이너 객체의 이질성에 대한 또 다른 시도는 std :: tuple을 사용하는 것이었지만, initializer_list가 확실히 튜플을 포함 할 수 있지만,이 접근법은 컴파일 타임 타입 분해도 무시합니다. 1999 년에 작성된 Heterogeneous, Nested STL Containers in C++이라는 논문이 템플릿 템플릿 인수를 사용하여 이질성 문제를 해결하는 것으로 나타났습니다. 이 모든 후, 나는 여기에 나의 게시로 이끄는 계급 같은 노동 조합에 정착했다. 비 관련/이종 컨테이너 객체에 대한 클래스와 같은 조합은 완벽한 메시지 선언 명확성, 객체 크기 모호성을 가지지 않으며 템플릿을 컴파일 할 수있는 시간을 가지며 우수한 다운 스트림 유지 관리 시나리오를 이끌어냅니다.
편집 2 : (5 주 후) 다음은 일어난 일입니다. 1)이 게시에서 조언을 준 전체 클래스와 유사한 조합 솔루션을 구현했습니다. 결과는 지루하고 다루기 힘들었고 '태그'는 각 하위 기능을 호출 할 하위 방법을 식별하는 데 사용되었습니다. 코드 유지 보수에 관한 낮은 등급. 2) C++ 17이 std :: variant를 승인했습니다. 현재 VS2015 Update 2에서는 아직 구현되지 않았으므로 boost :: variant를 사용하도록 설정했습니다. Visitor 패턴을 사용하여 초기화 된 변형 멤버 및 멤버 함수에 액세스 할 수있게하는 What is the right c++ variant syntax for calling a member function set to a particular variant?을 참조하십시오. 이렇게하면 '태그'스위치와 변형 'get'호출이 제거됩니다. 최종선 : 클래스와 유사한 유니온을 삭제하고 initializer_list를 사용하여 컴파일 타임에 초기화 가능한 모든 멤버 함수를 저장하는 유지 보수 가능한 코드를 만들기위한 변형을 채택했습니다 (읽기 : 유지 관리 용이).
먼저,'S' 복사 생성자가 실제로 작동하도록하십시오. 's.tag '이 무엇인지에 따라 복사 구조에 의해'B' 또는'C'를 생성해야합니다. 또한 소멸자가'tag '에 따라 올바른 타입을 파괴하도록하십시오. 클래스 밖에서 수동으로'new'와 소멸자를 호출하는 것을 피해야합니다. 형식 중 하나를 기본 생성자의 기본 형식으로 지정하십시오. – vu1p3n0x
복사 생성자가 업데이트되었습니다. – rtischer8277