최근에 Reddit 토론을 따라 std::visit
컴파일러 에서 최적화를 훌륭하게 비교했습니다 . 나는 다음을 발견했다 : https://godbolt.org/z/D2Q5ED
GCC9와 Clang9 (모두 동일한 stdlib를 공유한다고 생각합니다)는 모든 유형이 특정 조건을 충족 할 때 가치없는 예외를 확인하고 던지는 코드를 생성하지 않습니다. 이것은 더 나은 codegen으로 이어 지므로 MSVC STL에 문제가 발생 했으며이 코드가 표시되었습니다.
template <class T>
struct valueless_hack {
struct tag {};
operator T() const { throw tag{}; }
};
template<class First, class... Rest>
void make_valueless(std::variant<First, Rest...>& v) {
try { v.emplace<0>(valueless_hack<First>()); }
catch(typename valueless_hack<First>::tag const&) {}
}
주장은 이것이 변형을 무가치하게 만들고 문서를 읽는 것이 다음과 같아야한다는 것입니다.
먼저 현재 포함 된 값 (있는 경우)을 삭제합니다. 그런 다음
T_I
인수를 사용하여 유형의 값을 구성하는 것처럼 포함 된 값을 직접 초기화합니다std::forward<Args>(args)....
. 예외가 발생하면*this
valueless_by_exception이 될 수 있습니다.
내가 이해하지 못하는 것 : 왜 "may"라고 표시되어 있습니까? 전체 작업이 실패하면 이전 상태를 유지하는 것이 합법입니까? 이것이 GCC가하는 일이기 때문에 :
// For suitably-small, trivially copyable types we can create temporaries
// on the stack and then memcpy them into place.
template<typename _Tp>
struct _Never_valueless_alt
: __and_<bool_constant<sizeof(_Tp) <= 256>, is_trivially_copyable<_Tp>>
{ };
그리고 나중에 (조건부) 다음과 같은 작업을 수행합니다.
T tmp = forward(args...);
reset();
construct(tmp);
// Or
variant tmp(inplace_index<I>, forward(args...));
*this = move(tmp);
따라서 기본적으로 임시를 생성하고 복사가 성공하면 실제 위치로 복사 / 이동합니다.
IMO는 문서에 명시된대로 "먼저 포함 된 값을 삭제합니다"를 위반합니다. 표준을 읽으면 v.emplace(...)
변형의 현재 값이 항상 삭제되고 새 유형이 설정 유형이거나 값이없는 것입니다.
조건 is_trivially_copyable
에 관찰 가능한 소멸자가있는 모든 유형이 제외됩니다. 따라서 "as-if variant가 이전 값으로 다시 초기화 된 경우"와 같이 될 수도 있습니다. 그러나 변형의 상태는 관찰 가능한 효과입니다. 그렇다면 표준이 실제로 허용 emplace
합니까? 현재 값을 변경하지 않습니까?
표준 인용문에 대한 응답으로 편집하십시오.
그런 다음 포함 된 값을 인수가 아닌 TI 유형의 값을 직접 초기화하지 않는 것처럼 초기화합니다
std::forward<Args>(args)...
.
T tmp {std::forward<Args>(args)...}; this->value = std::move(tmp);
실제로 위의 유효한 구현으로 간주 됩니까 ? 이것이 "있는 것처럼"의 의미입니까?
might/may
표준에 대안이 무엇인지 명시하지 않기 때문에 나는 문구에 매우 혼란스러워합니다 .