C++ 如何使静态断言块在模板类中可重用?

C++ 如何使静态断言块在模板类中可重用?,c++,class,templates,c++17,static-assert,C++,Class,Templates,C++17,Static Assert,假设我有一个生成多个静态断言的模板类: template <class T> class Foo { static_assert(!std::is_const<T>::value,""); static_assert(!std::is_reference<T>::value,""); static_assert(!std::is_pointer<T>::value,""); //...<snip>...

假设我有一个生成多个静态断言的模板类:

template <class T>
class Foo
{
    static_assert(!std::is_const<T>::value,"");
    static_assert(!std::is_reference<T>::value,"");
    static_assert(!std::is_pointer<T>::value,"");

    //...<snip>...
}
模板
福班
{
静态断言(!std::is_const::value,“”);
静态断言(!std::is_reference::value,“”);
静态_断言(!std::is_指针::值“”);
//......
}
现在假设我有更多的模板类需要进行相同的断言


有没有办法使
静态断言
块可重用?一个“静态断言函数”,如果您愿意。

您可以将所需的特征组合成一个具有描述性名称的特征:

template<typename T> using
is_fancy = ::std::integral_constant
<
    bool
,   (not std::is_const<T>::value)
    and
    (not std::is_reference<T>::value)
    and
    (not std::is_pointer<T>::value)
>;
使用
是积分常数吗
<
布尔
,(不是std::is_const::value)
和
(非标准::is_参考::值)
和
(非标准::is_指针::值)
>;
以后再使用它:

static_assert(std::is_fancy<T>::value,"");
static_断言(std::is_fancy::value,”);

你可以做的一件事是建立一个新的特质,它是你想要检查的特质之一。因为你想否定所有这些可以转化为

template<typename T>
using my_trait = std::conjunction<std::negation<std::is_const<T>>,
                                  std::negation<std::is_reference<T>>,
                                  std::negation<std::is_pointer<T>>>;

static_assert(my_trait<int>::value, "");

您可以定义一个
constexpr bool
,它在编译时进行计算:

template<typename T>
inline constexpr bool is_okay_type = !std::is_const<T>::value &&
                                     !std::is_reference<T>::value &&
                                     !std::is_pointer<T>::value;
模板
inline constexpr bool是\u好的\u类型=!std::is_const::value&&
!std::is_reference::value&&
!std::is_pointer::value;
然后:

  • 直接使用它,就像您在示例中所做的那样:

    template<typename T> class MyClass
    {
        static_assert(is_okay_type<T>, "message");
    public:
        //...code...
    };
    
    模板类MyClass
    {
    静态断言(类型为“消息”);
    公众:
    //…代码。。。
    };
    
  • 或者您可以对模板类进行条件实例化, 取决于模板参数

    template<typename Type, typename Enable = void> class Class1;
    
    template<typename Type>
    class Class1<Type, std::enable_if_t<is_okay_type<Type>> >
    {
        //...code...
    };
    
    模板类Class1;
    模板
    一班
    {
    //…代码。。。
    };
    

  • 我已经看到了一些很好的答案,使用连词。 不幸的是,这些都很难调试。我曾经不得不调试一个类中的问题,说明:满足了需求。这是一个太长的列表,无法理解。我最终一个接一个地复制了所有的基础检查

    如果可能,我喜欢将它们分开:

    template<typename T>
    struct CustomCheck {
         static_assert(check<T>);
          // ...
     };
    
    模板
    结构自定义检查{
    静态断言(检查);
    // ...
    };
    
    在类中,您只需实例化它即可获得检查和详细错误:

     constexpr static CustomCheck<T> check{};
    
    constexpr静态自定义检查{};
    
    如果我正确理解了您所说的
    static\u assert
    块是什么意思,看起来您可以将这些assert放入一个模板类中,并从中导入heri
    Foo
    。如果您喜欢代码,请告诉我。这完全是一个偏好问题,但我宁愿从
    bool_constant
    @SergeyA继承,尽管我通常只声明一个别名,因为继承似乎会给编译器带来更多负担。关于继承与别名的编译时成本的有趣观察。从未检查过,你是如何衡量的?@SergeyA实例化一个新类型通常比解析一个alias@SergeyA“度量”可能是一个大胆的术语,但一段时间以来,我一直在与编译器(gcc)在一些相对模板密集的代码基础上耗尽RAM而导致的编译失败作斗争。限制新模板类型的生成(特别是以递归方式)被证明是对抗它们的最有效的方法。@JeJo这是另一个有效的选项。给这只猫剥皮有很多种方法。我只是不想引入任何实际变量。@SergeyA哇。我搞砸了。谢谢你的到场。我已经更新了答案。
     constexpr static CustomCheck<T> check{};