【问题标题】:How to make static_assert block re-usable in template classes?如何使 static_assert 块在模板类中可重用?
【发布时间】:2019-09-11 22:41:14
【问题描述】:

假设我有一个创建多个 static_asserts 的模板类:

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>...
}

现在说我有更多的模板类需要做出相同的断言。

有没有办法让static_assert 块可重用?如果你愿意的话,一个“static_assert 函数”。

【问题讨论】:

  • 如果我正确理解了static_assert 块的含义,看起来您可以将这些断言放入模板类并从中继承Foo。如果您想要代码,请告诉我。

标签: c++ class templates c++17 static-assert


【解决方案1】:

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

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)
>;

并在以后使用它:

static_assert(std::is_fancy<T>::value,"");

【讨论】:

  • 完全是一个偏好问题,但我宁愿从bool_constant继承。
  • @SergeyA 好点,虽然我通常只声明一个别名,因为继承似乎给编译器带来了更多负担。
  • 关于继承与别名的编译时成本的有趣观察。从来没有检查过,你是怎么测量的?
  • @SergeyA 实例化一个新类型通常比解析别名更难
  • @SergeyA "measure" 可能是一个大胆的术语,但一段时间以来,我一直在与编译器 (gcc) 在一些相对模板繁重的代码库上耗尽 RAM 导致的编译失败作斗争.并且限制新模板类型的产生(尤其是递归方式)被证明是对抗它们的最有效方法。
【解决方案2】:

您可以做的一件事是构建一个新特征,它是您要检查的特征的conjunction。既然你想要否定所有那些字面上会转化为的特征

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, "");

但是对于每个特征都必须使用std::negation 是/可能是一种痛苦。尽管使用std::disjunction 来获得所有特征的“或”,但您可以摆脱它,然后像您所做的那样否定静态断言中的值,从而为您提供

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

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

【讨论】:

  • @JeJo 这是另一个有效的选项。有很多方法可以给这只猫剥皮。我只是不想引入任何实际变量。
  • @SergeyA 哇。我搞砸了。谢谢现场。我已经更新了答案。
【解决方案3】:

我已经看到了一些很好的答案,使用了连词。 不幸的是,这些真的很难调试。我曾经不得不调试我的班级的一个问题,说明:满足要求。这是一个太长的列表,无法理解。我终于把所有的底层支票都一一复制了。

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

template<typename T>
struct CustomCheck {
     static_assert(check<T>);
      // ...
 };

在您的课程中,您只需实例化它即可获得检查和详细错误:

 constexpr static CustomCheck<T> check{};

【讨论】:

    【解决方案4】:

    您可以定义一个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;
    

    然后:

    1. 直接使用static_assert&lt;&gt;,就像您在示例中所做的那样:

      template<typename T> class MyClass
      {
          static_assert(is_okay_type<T>, "message");
      public:
          //...code...
      };
      
    2. 或者您可以对模板类进行条件实例化, 取决于模板参数。

      template<typename Type, typename Enable = void> class Class1;
      
      template<typename Type>
      class Class1<Type, std::enable_if_t<is_okay_type<Type>> >
      {
          //...code...
      };
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 2021-06-14
      • 1970-01-01
      • 2023-01-10
      相关资源
      最近更新 更多