如何写`is_complete`模板?

Kir*_*sky 21 c++ templates type-traits

回答完这个问题后,我试图is_complete在Boost库中找到模板,我意识到Boost.TypeTraits中没有这样的模板.为什么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 );
Run Code Online (Sandbox Code Playgroud)

上面的代码不正确,因为应用于sizeof不完整类型是非法的.什么是好的解决方案?在某种程度上可以在这种情况下应用SFINAE吗?


嗯,这个问题一般不会在不违反ODR规则的情况下解决,但是有一个特定于平台的解决方案对我有用.

J. *_*eja 14

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
Run Code Online (Sandbox Code Playgroud)

不幸的是,COUNTER预定义的宏不是标准的一部分,所以它不适用于每个编译器.

  • 这违反了ODR规则.计数器在一个翻译单元中为您提供多个不同的专业,但如果您在第二个文件中使用它,相同的专业化将获得不兼容的定义.解决方案是将其放在一个未命名的命名空间中. (4认同)
  • 可以使用“__LINE__”代替“__COUNTER__”。`__LINE__` 是标准的。 (2认同)

mis*_*why 11

可能有点晚了,但到目前为止,没有C++ 11解决方案适用于完整和抽象类型.

所以,你在这里.

使用VS2015(v140),g ++> = 4.8.1,clang> = 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
{};
Run Code Online (Sandbox Code Playgroud)

感谢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 >
{};
Run Code Online (Sandbox Code Playgroud)

这个灵感来自于互联网和静态断言模板类型名称T不完整?

  • 在我测试过的所有编译器上对我来说都非常完美,并且对自定义类型特征遵循更熟悉的风格,而不依赖于实现特定的 `__COUNTER__` 值。我相信这是比公认的答案更好的解决方案。 (2认同)
  • 如果我转发声明一个类型,使用这个特性,然后定义它并再次使用它,这似乎不起作用。它对两者都产生错误。在 gcc.godbolt.org 上尝试使用主干 GCC/Clang。https://gcc.godbolt.org/z/pegeNa (2认同)
  • @SanduLiviuCatalin 像这样工作正常:https://gcc.godbolt.org/z/HFGdZA。所以我猜您已经发现了一个错误,您可以通过重新排序定义来解决该错误。我认为这与模板在这个编译单元中被评估一次有关。 (2认同)

Ale*_*tov 9

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;
};
Run Code Online (Sandbox Code Playgroud)

  • 很好,但正如@litb在他的评论中所说,如果is_complete <type>出现在同一文件中的两个相互矛盾的位置,当类型类型的定义出现在它们之间时,它无法正常工作(我试过:)). (4认同)

Gre*_*osz 5

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

\n\n
\n

错误:初始化 \xe2\x80\x98static char 的参数 1 (& is_complete::pass(T))[2] [with T = Foo]\xe2\x80\x99

\n
\n\n

在我的 Mac 上,使用 G++ 4.0.1 评估不完整的is_complete<Foo>::value地方会产生比编译器错误更糟糕的结果。struct Foo;true

\n\n

T在同一个程序中可以是完整的也可以是不完整的,具体取决于翻译单元,但它始终是相同的类型。因此,如上所述,is_complete<T>也始终是相同的类型。

\n\n

因此,如果您尊重ODR,则不可能is_complete<T>根据其使用位置评估不同的值;is_complete<T>否则,这将意味着您有ODR 禁止的不同定义。

\n\n

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

\n