【问题标题】:How to use static_assert used with a member initilizer list如何使用与成员初始化器列表一起使用的 static_assert
【发布时间】:2015-11-26 04:12:24
【问题描述】:

我想使用 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.");
};

Main.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_path\Some_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_path\Some_Class.cpp(3,2): error : use of 'this' in a constant expression

【问题讨论】:

  • 如果有人Some_Class foo6(getCurrentTimeInMilliseconds() % 1000);怎么办?
  • 静态断言在编译时执行。函数参数在运行时传递。我建议使用常规断言。
  • 啊,该死,我才意识到。有没有办法在编译时强制对构造函数进行函数参数检查,或者这实际上只是保证一个新问题?也许以某种方式抛出 constexpr 可能会有所帮助。
  • @NeilKirk 我在一个相对最小的嵌入式系统上,因此即使经过优化,assert 添加的大约 4KB 的代码对于我的环境来说也太多了。我希望使用 static_assert,因为根据我的理解,它应该引入最小(如果不是零)额外代码大小。
  • 什么?断言通常在发布版本中被禁用。 4kb 是从哪里来的?

标签: c++ c++11 enums c++14 static-assert


【解决方案1】:

参数值不能用于 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;
    };
    
  • 传递一个integral_constant:

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

【讨论】:

    【解决方案2】:

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

    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>();
    

    如果有人从该类派生并公开构造函数,则在构造函数中添加正常断言。

    【讨论】:

    • 为什么不把构造函数做成模板呢?
    • @NeilKirk 这是一个有趣的想法,但在快速谷歌搜索并编写了一些代码之后,我似乎无法让构造函数成为模板。根据您的评论,我正在为我的原始答案添加替代方案。
    猜你喜欢
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 2015-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-15
    • 1970-01-01
    相关资源
    最近更新 更多