在静态断言中解决不完整类型

时间:2017-03-14 06:28:47

标签: c++ templates typetraits static-assert

当表达式依赖于类类型本身时,是否有一种方法可以在类中使用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;
}

5 个答案:

答案 0 :(得分:2)

这是一个使用辅助类和间接类型别名的解决方案。我相信这没有任何缺点。

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;

答案 1 :(得分:1)

我也在寻找带有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;
}

答案 2 :(得分:0)

你可以定义一个析构函数并将static_assert放在那里,至少用g ++ 5.4 -std = c ++ 11这个有效。

答案 3 :(得分:0)

(从评论中移出)

您可以添加一个中间类来保留逻辑,并让您的客户端实例化一个派生的,只包含static_assert

#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
};

答案 4 :(得分:0)

我不知道这是否完全合规,但两者都gcc trunk and clang trunk accept this

#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 时它不起作用。天啊。

不过,这会使您的类型成为非聚合类型。


如果您的类型具有任何强制成员函数,您可以将 static_assert 放在这些函数体之一中。成员函数体在类定义结束后求值,因此不会看到不完整的类型。

对于模板,问题在于并非所有成员函数总是被实例化。非实例化成员函数中的 static_assert 不会触发。您需要在代码中的某处调用(实际上是任何 ODR 使用)来强制实例化。