模板或类中的static_assert陷阱

时间:2019-03-06 10:42:07

标签: c++

关于这个主题,我读了一些相关的SO问题/解答/评论。仅找到一个相关但有些隐晦的问题/答案here。请允许我尝试以问题/答案的方式清楚地显示问题。为了他人的利益。

让代码说话。想象您设计了这个模板。

// 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>, "\n\nNo references!\n\n");
    static_assert(!std::is_array_v<T>, "\n\nNo arrays!\n\n");

    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;

静态断言消息确实突然显示。但是“测试”如何编译和通过的呢?这是怎么回事?

1 个答案:

答案 0 :(得分:1)

问题是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>, "\n\nNo references!\n\n");
    static_assert(!std::is_array_v<T>, "\n\nNo arrays!\n\n");

    using value_type = T;
    T value;
};

用户在此处进行了适当的编码,以从模板转换为类型,但是,static_assert的功能不起作用:

    using naivete = no_arrf_naive<arf>;

最令人担忧的是,直到有人想要使用此功能时,它才会被忽略。那将不会编译,API作者放置在其中的消息将最终显示。但是a,为时已晚。

在使用某些大型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 ++建议。对于他们来说,这既不平凡也不无用。

非常感谢您阅读。