clang, msvc 可以编译通过, gcc 不行
时间: 2020-08-27来源:V2EX
前景提要
我又来问问题啦,这回还是喜闻乐见的 C++问题,同样一份代码 MSCVC 19.24 ,clang 10 均可编译通过,g++-10 不可编译通过,这是什么原因呢,注意,须加入参数要求 compiler 支持 C++17 (-std=c++17), 可在线编译版本代码链接 https://godbolt.org/z/eWhsne ,源码如下, 其中开头部分的 type_traits 应该是没问题的,主要问题集中在 gcc 对 fold expression 的处理上,这份代码是对 std::variant 部分简单不完全实现 #include <type_traits> #include <utility> #include <new> #include <cassert> #include <exception> template <bool COND, typename TrueType, typename FalseType> class IfThenElseT { public: using Type = TrueType; }; template <typename TrueType, typename FalseType> class IfThenElseT<false, TrueType, FalseType> { public: using Type = FalseType; }; template <bool COND, typename TrueType, typename FalseType> using IfThenElse = typename IfThenElseT<COND, TrueType, FalseType>::Type; template <typename... Elements> class Typelist { }; template <typename List> class FrontT; template <typename Head, typename... Tail> class FrontT<Typelist<Head, Tail...>> { public: using Type = Head; }; template <typename List> using Front = typename FrontT<List>::Type; template <typename List> class PopFrontT; template <typename Head, typename... Tail> class PopFrontT<Typelist<Head, Tail...>> { public: using Type = Typelist<Tail...>; }; template <typename List> using PopFront = typename PopFrontT<List>::Type; template <typename List> class IsEmpty { public: static constexpr bool value = false; }; template <> class IsEmpty<Typelist<>> { public: static constexpr bool value = true; }; template <typename List, typename T, unsigned N = 0, bool Empty = IsEmpty<List>::value> struct FindIndexOf { }; template <typename List, typename T, unsigned N> struct FindIndexOf<List, T, N, false> : public IfThenElse<std::is_same_v<Front<List>, T>, std::integral_constant<unsigned, N>, FindIndexOf<PopFront<List>, T, N + 1>> { }; template <typename List, typename T, unsigned N> struct FindIndexOf<List, T, N, true> { }; template <typename List> class LargestTypeT; template <typename List> class LargestTypeT { private: using First = Front<List>; using Rest = typename LargestTypeT<PopFront<List>>::Type; public: using Type = IfThenElse<(sizeof(First) >= sizeof(Rest)), First, Rest>; }; template <> class LargestTypeT<Typelist<>> { public: using Type = char; }; template <typename List> using LargestType = typename LargestTypeT<List>::Type; template <typename... Types> class VariantStorage { private: using LargestT = LargestType<Typelist<Types...>>; alignas(Types...) unsigned char buffer[sizeof(LargestT)]; unsigned char discriminator = 0; public: unsigned char getDiscriminator() { return discriminator; } void setDiscriminator(unsigned char d) { discriminator = d; } void *getRawBuffer() { return buffer; } void const *getRawBuffer() const { return buffer; } template <typename T> T *getBufferAs() { return std::launder(reinterpret_cast<T *>(buffer)); } template <typename T> T const *getBufferAs() const { return std::launder(reinterpret_cast<T const *>(buffer)); } }; template <typename... Types> class Variant; template <typename T, typename... Types> class VariantChoice { private: using Derived = Variant<Types...>; Derived &getDerived() { return *static_cast<Derived *>(this); } Derived const &getDerived() const { return *static_cast<Derived const *>(this); } protected: constexpr static unsigned Discriminator = FindIndexOf<Typelist<Types...>, T>::value + 1; public: VariantChoice() = default; VariantChoice(T const &value); VariantChoice(T &&value); bool destroy(); Derived &operator=(T const &value); Derived &operator=(T &&value); }; template <typename T, typename... Types> VariantChoice<T, Types...>::VariantChoice(T const &value) { new (getDerived().getRawBuffer()) T(value); getDerived().setDiscriminator(Discriminator); } template <typename T, typename... Types> VariantChoice<T, Types...>::VariantChoice(T &&value) { new (getDerived().getRawBuffer()) T(std::move(value)); getDerived().setDiscriminator(Discriminator); } template <typename T, typename... Types> bool VariantChoice<T, Types...>::destroy() { if (getDerived().getDiscriminator() == Discriminator) { getDerived().template getBufferAs<T>()->~T(); return true; } return false; } template <typename T, typename... Types> auto VariantChoice<T, Types...>::operator=(T const &value) -> Derived & { if (getDerived().getDiscriminator() == Discriminator) { *getDerived().template getBufferAs<T>() = value; } else { getDerived().destroy(); new (getDerived().getRawBuffer()) T(value); getDerived().setDiscriminator(Discriminator); } return getDerived(); } template <typename T, typename... Types> auto VariantChoice<T, Types...>::operator=(T &&value) -> Derived & { if (getDerived().getDiscriminator() == Discriminator) { *getDerived().template getBufferAs<T>() = std::move(value); } else { getDerived().destroy(); new (getDerived().getRawBuffer()) T(std::move(value)); getDerived().setDiscriminator(Discriminator); } return getDerived(); } class ComputedResultType; class EmptyVariant : public std::exception { }; template <typename... Types> class Variant : private VariantStorage<Types...>, private VariantChoice<Types, Types...>... { template <typename T, typename... OtherTypes> friend class VariantChoice; public: using VariantChoice<Types, Types...>::VariantChoice...; //g++报错 using VariantChoice<Types, Types...>::operator=...; //g++报错 template <typename T> bool is() const; template <typename T> T &get() &; template <typename T> T &&get() &&; template <typename T> T const &get() const &; // template <typename R=ComputedResultType, typename Visitor> // VisitResult<R, Visitor bool empty() const; void destroy(); ~Variant() { destroy(); } private: }; template <typename... Types> template <typename T> bool Variant<Types...>::is() const { return this->getDiscriminator() == VariantChoice<T, Types...>::Discriminator; //g++报错 } template <typename... Types> template <typename T> T &Variant<Types...>::get() & { if (empty()) { throw EmptyVariant(); } assert(is<T>()); return *this->template getBufferAs<T>(); } template <typename... Types> template <typename T> T &&Variant<Types...>::get() && { if (empty()) { throw EmptyVariant(); } assert(is<T>()); return *this->template getBufferAs<T>(); } template <typename... Types> template <typename T> T const &Variant<Types...>::get() const & { if (empty()) { throw EmptyVariant(); } assert(is<T>()); return *this->template getBufferAs<T>(); } template <typename... Types> void Variant<Types...>::destroy() { // bool results[] = {VariantChoice<Types, Types...>::destroy()...}; (VariantChoice<Types, Types...>::destroy(), ...); //g++报错 this->setDiscriminator(0); } int main() { Variant<int> v{17}; return 0; }

科技资讯:

科技学院:

科技百科:

科技书籍:

网站大全:

软件大全:

热门排行