如何使用与成员初始化器列表一起使用的static_assert

How to use static_assert used with a member initilizer list

本文关键字:static assert 一起 列表 何使用 成员 初始化      更新时间:2023-10-16

我想使用static_assert来对类的配置实施各种限制。早些时候,我只使用一个枚举,并且只允许一个构造函数,该构造函数需要所述枚举来对我的类强制执行限制。如果我有下面这样的东西,并且范围是从0到4,这很好,但一旦我有了0到500的范围,那么使用枚举就变得很难了。

Some_Class.h

class Some_Class {
    public:
        Some_Class(const unsigned int param);
    private:
        const unsigned int member_param;
};

Some_Class.cpp

Some_Class::Some_Class(const unsigned int param) : member_param(param) {
    static_assert(member_param < 500, "Param must be less than 500.");
};

主要.cpp

Some_Class foo4(125); // OK
Some_Class foo5(500); // Should fail at compile time.

这就是GCC在使用C++14进行编译时向我抛出的问题:

1>  Some_Class.cpp: In constructor 'Some_Class::Some_Class(unsigned int)':
1>C:some_pathSome_Class.cpp(3,2): error : non-constant condition for static assertion
1>    static_assert(member_param < 500, "Param must be less than 500.");
1>    ^
1>C:some_pathSome_Class.cpp(3,2): error : use of 'this' in a constant expression

参数值不能在constexpr中使用。

您必须以某种方式提交编译时值:

  • 模板你的整个类:

    template<unsigned int size>
    class Some_Class {
        static_assert(size < 500, "Size should be less than 500");
    public:
        constexpr unsigned int member_param = size;
    };
    
  • 传递一个积分常数:

    template <unsigned int N>
    using uint_c = std::integral_constant<unsigned int, N>;
    class Some_Class {
    public:
        template<unsigned int size>
        Some_Class(uint_c<size>) : member_param(size)
        {
            static_assert(size < 500, "Size should be less than 500");
        }
    private:
        unsigned int member_param;
    };
    

如果你想要编译时检查,你应该使用模板:

template<int size>
class Some_Class {
public:
    Some_Class() : member_param(size) { static_assert(size < 500, "Size should be less than 500"); }
private:
    const unsigned int member_param;
}

然后使用类,用户必须明确指定大小:

void myFunction() {
    Some_Class<20> class20; // Works
    Some_Class<500> class500; // Compiler error
}

编辑:根据@NeilKirk的评论,以下代码将在不必使整个类成为模板的情况下实现相同的效果:

class Some_Class {
public:
    template<int size>
    static Some_Class* createClass() {
        static_assert(size < 500, "Size should be less than 500");
        return new Some_Class(size);
    }
private:
    Some_Class(int size) : member_param(size) { assert(size < 500); }
private:
    const unsigned int member_param;
};

它的作用:构造函数接受大小,但却是私有的。因此,必须使用作为模板的createClass静态函数来创建类,并且可以对大小执行static_assert。

创建对象:

Some_Class* class = Some_Class::createClass<20>();

如果有人从类派生并将构造函数公开,则在的构造函数中添加普通断言。