简体   繁体   English

根据某种条件在编译时生成一个字符串

[英]generate a string at compile time based on some condition

I wanted to generate fopen() 's open mode parameter at compile-time ( file::get_mode() ) 我想在编译时生成fopen()的打开模式参数( file::get_mode()

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

enum open_mode {
    read = (1u << 0),
    write = (1u << 1),
    binary = (1u << 2),
    update = (1u << 3)
};

template<int open_type>
class file {
public:
    constexpr static int is_read_mode() {
        return CHECK_BIT(open_type,0);
    }
    constexpr static int is_write_mode() {
        return CHECK_BIT(open_type,1);
    }
    constexpr static int is_binary_mode() {
        return CHECK_BIT(open_type,2);
    }
    constexpr static int is_update_mode() {
        return CHECK_BIT(open_type,3);
    }
    constexpr static const void get_mode(char (&mode)[5]) {
        int len = 0;
        if constexpr(is_read_mode())
            mode[len++] = 'r';
        if constexpr(is_write_mode())
            mode[len++] = 'w';
        if constexpr(is_binary_mode())
            mode[len++] = 'b';
        if constexpr(is_update_mode())
            mode[len++] = '+';
        mode[len++] = 0;
    }    
};

but even though everything inside the file::get_mode() can be determined at compile-time (as far as I can think) but i don't think it's computing at compile-time as the following code is not compiling because of the last assertion, removing the last assertion code compiles fine and runs 但是即使file::get_mode()内的所有内容都可以在编译时确定(据我所知),但是我不认为它在编译时正在计算,因为以下代码由于最后一个而无法编译断言,删除最后的断言代码可以正常编译并运行

int main() {
    file<open_mode::write> f; 
    char mode[5];
    f.get_mode(mode);
    static_assert(mode[0] == 'w');
}

so my question is: how can I generate this at compile-time? 所以我的问题是:如何在编译时生成此代码?

You're using if constexpr so you're using C++17. 您正在使用if constexpr因此您正在使用C ++ 17。

In C++17 the operator[] is constexp so, instead of passing and modifying a C-style array, you can generate an return a std::array . 在C ++ 17中, operator[]constexp因此可以传递std::array而不是传递和修改C样式的std::array

I mean 我的意思是

constexpr static auto get_mode ()
    {
      std::array<char, 5U> ret {}; // initialize to `\0` all chars

      std::size_t pos = -1;

      if constexpr ( is_read_mode() ) ret[++pos] = 'r';
      if constexpr ( is_write_mode() ) ret[++pos] = 'w';
      if constexpr ( is_binary_mode() ) ret[++pos] = 'b';
      if constexpr ( is_update_mode() ) ret[++pos] = '+';

      return ret;
    }

so you can write something as 所以你可以写一些东西

static_assert( f.get_mode()[0] == 'w' );
static_assert( f.get_mode()[1] == '\0' );

En passant: remember to make is_*_mode() functions returning bool , not int . 注意:请记住使is_*_mode()函数返回bool ,而不是int

The following is a full compiling example 以下是完整的编译示例

#include <array>

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

enum open_mode {
    read = (1u << 0),
    write = (1u << 1),
    binary = (1u << 2),
    update = (1u << 3)
};

template <int open_type>
struct file
 {
   constexpr static bool is_read_mode() { return CHECK_BIT(open_type,0); }
   constexpr static bool is_write_mode() { return CHECK_BIT(open_type,1); }
   constexpr static bool is_binary_mode() { return CHECK_BIT(open_type,2); }
   constexpr static bool is_update_mode() { return CHECK_BIT(open_type,3); }

   constexpr static auto get_mode ()
    {
      std::array<char, 5U> ret {};

      std::size_t pos = -1;

      if constexpr ( is_read_mode() ) ret[++pos] = 'r';
      if constexpr ( is_write_mode() ) ret[++pos] = 'w';
      if constexpr ( is_binary_mode() ) ret[++pos] = 'b';
      if constexpr ( is_update_mode() ) ret[++pos] = '+';

      return ret;
    }
 };

int main ()
 {
   file<open_mode::write> fw; 

   static_assert( fw.get_mode()[0] == 'w' );
   static_assert( fw.get_mode()[1] == '\0' );

   file<open_mode::read | open_mode::write> frw; 

   static_assert( frw.get_mode()[0] == 'r' );
   static_assert( frw.get_mode()[1] == 'w' );
   static_assert( frw.get_mode()[2] == '\0' );
 }

char mode[5] is not constexpr , so it might change its values in runtime. char mode[5]不是constexpr ,因此它可能会在运行时更改其值。 Instead, you could return a string literal from get_mode() . 相反,您可以从get_mode()返回字符串文字。 You should also modify the logic to prevent invalid access modes (for example, if you want both read and write, you should use w+ or r+ , not wr ). 您还应该修改逻辑以防止无效的访问模式(例如,如果要同时进行读取和写入,则应使用w+r+ ,而不要使用wr )。

constexpr static const char* get_mode() {
    if (is_read_mode()) {
        if (is_binary_mode()) {
            return "rb";
        }
        else {
            return "r";
        }
    }
    // ...
}   

You can use it at compile time like this: 您可以在编译时使用它,如下所示:

int main() {
    file<open_mode::write> f; 
    static_assert(f.get_mode() == "w");
    static_assert(f.get_mode()[0] == 'w');
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 是否可以在编译时生成一个字符串? - Is it possible to generate a string at compile time? 基于模板编译时间字符串生成器 - Compile time string generator based on templates 基于编译时条件在类型之间进行选择的惯用法 - Idiomatic way of choosing between types based on a compile-time condition 基于条件的编译时类型选择的变量模板 - Variadic template for compile-time type selection based on condition 如何在编译时从字符串生成boost uuid - How to generate boost uuid from string at compile time 如果条件取决于模板类型并且在编译时已知,是否可以保证 C++ 编译器不会生成分支? - Is it guaranteed that C++ compiler won't generate branch if the condition depends on the template type and is known at compile time? 基于参数构建编译时 sql 查询字符串 - Build compile time sql query string based on parameters [C ++编译时断言]:如果不满足某些条件,我们可以抛出编译错误吗? - [C++ compile time assertions]: Can we throw a compilation error if some condition is not met? 如果某些成员函数尚未被调用,是否可能产生编译时错误 - Is it possible to generate a compile-time error if some member function hasn't been called 在编译时生成唯一的数字 - Generate unique numbers at compile time
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM