围绕静态断言不完整的类型

Work around incomplete type in static assert

本文关键字:类型 静态 断言      更新时间:2023-10-16

当表达式取决于类类型本身时,是否有一种方法可以在类中static_assert?也许将评估延迟到模板实例化完成或之后的类型?

示例代码:

#include <type_traits>
template<typename T>
struct Test {
   T x = 0; // make non-trivial
   static_assert(std::is_trivial<Test<T>>::value, "");
};
int main() {
    // would like static assert failure, instead get 'incomplete type' error
    Test<int> test1;
    Test<float> test2;
    return 0;
}

这是一种使用助手类和间接类型的解决方案。我相信这没有缺点。

template<typename T>
struct TestImpl {
    T x = 0; // make non-trivial
};
template<typename T>
struct TestHelper {
    using type = TestImpl<T>;
    static_assert(std::is_trivial<type>::value, "");
};
template<typename T>
using Test = typename TestHelper<T>::type;

编辑:可以将testHelper移至testimpl:

template<typename T>
struct TestImpl {
    T x = 0; // make non-trivial
    struct Helper {
        using type = TestImpl;
        static_assert(std::is_trivial<type>::value, "");
    };
};
template<typename T>
using Test = typename TestImpl<T>::Helper::type;

我也在寻找使用static_assert的解决方案,但约束也有效:

#include <type_traits>
namespace Private {
template<typename T>
struct Test {
   T x = 0;
};
}
template<typename T>
requires std::is_trivial<Private::Test<T>>::value
using Test = Private::Test<T>;
int main() {
    Test<int> test1;
    Test<float> test2;
    return 0;
}

您可以定义击曲线并将static_assert放在那里,至少使用G 5.4 -STD = C 11这可以使用。

(从评论移动)

您可以添加一个中间类以保持逻辑,并让您的客户实例化派生的类别,该类别仅包含static_assert S

#include <type_traits>
template<typename T>
struct TestImpl {
    T x = 0; // make non-trivial
};
template<typename T>
struct Test : TestImpl<T> {
    static_assert(std::is_trivial<TestImpl<T>>::value, "");
    using TestImpl<T>::TestImpl; // inherit constructors
};

我不知道这是否完全合规,但GCC中继和clang trunk都接受了:

#include <type_traits>
template<typename T>
constexpr bool check_trivial()
{
    static_assert(std::is_trivial_v<T>);
    return std::is_trivial_v<T>;
}
template<typename T>
struct Test
{
   Test() noexcept(check_trivial<Test<T>>()) = default;
   T x;
};
struct nontrivial
{
    nontrivial(){}
};
int main() {
    // would like static assert failure, instead get 'incomplete type' error
    Test<int> test1;
    Test<nontrivial> test2;
    return 0;
}

使用DTOR而不是CTOR时它不起作用。YMMV。

这使您的类型成为非聚集。


如果您的类型具有任何强制性成员功能,则可以将static_assert放在其中一个功能主体中。在类定义结束后对成员函数体进行评估,因此看不到不完整的类型。

对于模板,问题是并非所有成员函数始终是实例化的。在非实验性成员函数中的static_assert不会发射。您需要在代码中某个地方的某个地方进行呼叫(实际使用任何ODR使用)才能强制实例化。