代码之家  ›  专栏  ›  技术社区  ›  Kirill V. Lyadvinsky

如何编写“is_cocomplete”模板?

  •  31
  • Kirill V. Lyadvinsky  · 技术社区  · 16 年前

    回答后 this 我试图找到的问题 is_complete Boost库中的模板,我意识到Boost中没有这样的模板。类型特征。为什么Boost库中没有这样的模板?它应该是什么样子的?

    //! Check whether type complete
    template<typename T>
    struct is_complete
    {   
      static const bool value = ( sizeof(T) > 0 );
    };
    
    ...
    
    // so I could use it in such a way
    BOOST_STATIC_ASSERT( boost::is_complete<T>::value );
    

    sizeof 不完整的类型。什么是好的解决方案?


    ODR rule ,但有一个特定于平台的 solution

    8 回复  |  直到 4 年前
        1
  •  15
  •   L. F.    6 年前

    Alexey Malistov给出的答案可以在MSVC上使用,只需稍作修改:

    namespace 
    {
        template<class T, int discriminator>
        struct is_complete {  
          static T & getT();   
          static char (& pass(T))[2]; 
          static char pass(...);   
          static const bool value = sizeof(pass(getT()))==2;
        };
    }
    #define IS_COMPLETE(X) is_complete<X,__COUNTER__>::value
    

    不幸的是 __COUNTER__ 预定义宏不是标准的一部分,因此它不适用于每个编译器。

        2
  •  13
  •   Community Mohan Dere    8 年前

    这可能有点晚了,但到目前为止,还没有一个C++11解决方案同时适用于完整和抽象类型。

    那么,你来了。

    对于VS2015(v140),g++>=4.8.1,叮当声>=3.4,这是有效的:

    template <class T, class = void>
    struct IsComplete : std::false_type
    {};
    
    template <class T>
    struct IsComplete< T, decltype(void(sizeof(T))) > : std::true_type
    {};
    

    感谢Bat Ulzii Luvsanbat: https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/

    使用VS2013(V120):

    namespace Details
    {
    
        template <class T>
        struct IsComplete
        {
            typedef char no;
            struct yes { char dummy[2]; };
    
            template <class U, class = decltype(sizeof(std::declval< U >())) >
            static yes check(U*);
    
            template <class U>
            static no check(...);
    
            static const bool value = sizeof(check< T >(nullptr)) == sizeof(yes);
        };
    
    } // namespace Details
    
    
    template <class T>
    struct IsComplete : std::integral_constant< bool, Details::IsComplete< T >::value >
    {};
    

    static assert that template typename T is NOT complete?

        3
  •  9
  •   Alexey Malistov    16 年前
    template<class T>
    struct is_complete {
        static T & getT();
        static char (& pass(T))[2];
        static char pass(...);
    
        static const bool value = sizeof(pass(getT()))==2;
    };
    
        4
  •  4
  •   Gregory Pakosz    16 年前

    恐怕你不能实施这样的计划 is_complete 类型特征。@Alexey给出的实现在G++4.4.2和G++4.5.0上无法编译:

    在我的Mac上,使用G++4.0.1进行评估 is_complete<Foo>::value 哪里 struct Foo; 不完全屈服于 true 这甚至比编译器错误更糟糕。

    T is_complete<T>

    所以,如果你尊重 ODR 不可能有 已完成<T> 根据使用地点,评估为不同的值;否则,这意味着你对 已完成<T> ODR禁止的。

    编辑:作为公认的答案,我自己破解了一个使用 __COUNTER__ 宏实例化一个不同的 is_complete<T, int> 每次键入 IS_COMPLETE 使用宏。然而,有了gcc,我一开始就无法让SFINAE工作。

        5
  •  2
  •   Community Mohan Dere    8 年前

    解决这个问题需要在trait模板的默认参数中执行计算,因为试图更改模板的定义违反了ODR规则(尽管 __COUNTER__ namespace {} 可以绕过ODR)。

    这是用C++11编写的,但可以调整为在适度兼容C++11的编译器的C++03模式下工作。

    template< typename t >
    typename std::enable_if< sizeof (t), std::true_type >::type
    is_complete_fn( t * );
    
    std::false_type is_complete_fn( ... );
    
    template< typename t, bool value = decltype( is_complete_fn( (t *) nullptr ) )::value >
    struct is_complete : std::integral_constant< bool, value > {};
    

    Online demo.

    true 一个为 false .

    但要注意,在模板中使用它几乎肯定会违反ODR。在不完整类型上实例化的模板与在完整类型上初始化的模板不能有任何不同。我个人只想要这个 static_assert .

    顺便说一句,如果你想走另一条路,这个原则也可能有所帮助 implement __计数器__ 使用模板和重载。

        6
  •  2
  •   Fabio A. fredoverflow    8 年前

    is_complete<T> 模板。

    here 。我不会把它贴在下面,以免错误地获得赞誉。

        7
  •  1
  •   Jerry Coffin    16 年前

    我在标准中找不到任何东西可以保证不完整类型上的sizeof将产生0。然而,它确实要求,如果T在某个时候不完整,但在该翻译单元的稍后完成,则所有对T的引用都指向同一类型——因此,在我读到的时候,即使T在调用模板的地方不完整,如果T是在该翻译单元的某个地方完成的,也需要说它是完整的。

        8
  •  0
  •   김선달    4 年前

    这是一个老问题,但所提出的答案对于某些类型(如函数引用类型或cv限定的函数类型)并不正确。

    template<typename T, typename = void>
    struct is_complete_object : std::false_type {};
    
    template<typename T>
    struct is_complete_object<T, std::enable_if_t<(sizeof(T) > 0)>> : std::true_type {};
    
    template<typename T, bool v = std::is_object<T>::value /* true */>
    struct is_complete_impl : is_complete_object<T> {};
    
    template<typename T>
    struct is_complete_impl<T, false> : std::integral_constant<bool, !std::is_void<T>::value> {};
    
    template <typename T>
    struct is_complete : is_complete_impl<T> {};
    
    template<typename T>
    struct is_complete<T[]> : std::false_type {};
    
    template<typename T, size_t N>
    struct is_complete<T[N]> : is_complete<T> {};
    

    现在,这将适用于类函数类型。

        9
  •  0
  •   Sergey Kolesnik    4 年前