static_assert在模板或类中,gotcha

static_assert inside template or class, gotcha

本文关键字:gotcha assert static      更新时间:2023-10-16

在这个主题上,我读了很少的相关性,所以问题/答案/评论。在这里只发现了一个相关但有些掩埋的问题/答案。请允许我尝试以有关/答案方式清楚地显示问题。为了他人的利益。

让代码说话。想象一下您设计此模板。

// value holder V1.0
// T must not be reference or array or both
template<typename T> struct no_arrf_naive
{
    static_assert(!std::is_reference_v<T>, "nnNo references!nn");
    static_assert(!std::is_array_v<T>, "nnNo arrays!nn");
    using value_type = T;
    T value;
};

简单安全,可能会想。一段时间后,其他人将这个复杂的大型API埋葬在深处,然后开始使用它。上面的结构在内部深处。通常,他们只是使用它,而无需查看后面的代码。

        using arf = int(&)[3];
        using naivete = no_arrf_naive<arf>;
        // the "test" works
        constexpr bool is_ok_type = std::is_class_v< naivete >;
    // this declaration will also "work"
    void important ( naivete ) ;

但是。实例不起作用

    naivete no_compile;

静态断言消息确实突然显示了。但是,"测试"如何编译和通过?这里发生了什么?

问题是API是错误的。static_assert作为班级成员进行"踢入",但在实例化之前不做。

首先,有害的API评论

    template<typename T>
struct no_arrf_naive
{
    // member declarations
    // used  only on implicit instantiation
    // https://en.cppreference.com/w/cpp/language/class_template#Implicit_instantiation
    static_assert(!std::is_reference_v<T>, "nnNo references!nn");
    static_assert(!std::is_array_v<T>, "nnNo arrays!nn");
    using value_type = T;
    T value;
};

用户在这里正确编码以从模板转换为类型,但是static_assert的do not oke not oke of-not-not oken:

    using naivete = no_arrf_naive<arf>;

这可能最令人担忧的是,直到有人想使用它。这不会编译,并且消息是API作者放置在那里的消息,最终将显示。但是las,为时已晚。

以及在一些大型C 来源上工作的项目,出现的问题是最臭名昭著的问题。

解决方案是良好的旧sfinae。API修复是这样的:

 // value holder
 // references or arrays or both are excluded at compile time
    template<typename T,
    std::enable_if_t< 
      (!std::is_reference_v<T> && !std::is_array_v<T>), bool> = true
     > struct no_arrf
{
    using value_type = T;
    T value;
};

尝试使用引用或数组或两者从模板创建类型时,不会立即编译:

  // reference to array of three int's
  using arf = int(&)[3] ;
  // no can do
  using no_naivete = no_arrf<arf>;
  (MSVC) error C2972: 'no_arrf':
  template parameter 'unnamed-parameter': 
  the type of non-type argument is invalid

我可能会认为整个故事对某些人来说可能看起来很琐碎甚至没有用。但是,我相信许多好人会出于急需的标准C 建议。对于他们来说,这既不是微不足道的也不是无用的。

非常感谢您的阅读。