用户定义的文字字符串:编译时长度检查

时间:2017-11-29 01:22:38

标签: c++ c++11 static-assert compile-time-constant user-defined-literals

我有一个用户定义的文字运算符,只对特定长度的字符串有意义,如下所示:

constexpr uint16_t operator "" _int(const char* s, std::size_t len)
{
    return len == 2 ? s[0] | (s[1] << 8) : throw;
}

这有效:

"AB"_int // equals 16961

但这也是编译,我不想要它:

"ABC"_int // throws at runtime

我尝试static_assert(len == 2),但在constexpr功能中不允许这样做。

如何让"ABC"_int在编译时导致错误?

3 个答案:

答案 0 :(得分:1)

  

如何让"ABC"_int在编译时导致错误?

通过示例:初始化constexpr变量

constexpr auto foo = "ABC"_int;

否则(如果你不以某种方式强制编译时计算)编译器不会计算(不是强制的,但实际上是发生的事情)编译时,而是为运行时编译准备代码。

答案 1 :(得分:0)

#include <iostream>
#include <cstdint>
using namespace std;

constexpr uint16_t operator "" _int(char const * s, size_t len)
{
    return (len == 2) ? s[0] | (s[1] << 8) : throw "len must be 2!";
}

int main()
{
    constexpr uint16_t i1 = "AB"_int; // OK
    cout << i1 << endl; // outputs 16961

    constexpr uint16_t i2 = "ABC"_int; // error
    cout << i2 << endl;

    return 0;
}

prog.cpp: In function ‘int main()’:
prog.cpp:13:29:   in constexpr expansion of ‘operator""_int(((const char*)"ABC"), 3ul)’
prog.cpp:7:52: error: expression ‘<throw-expression>’ is not a constant-expression
     return (len == 2) ? s[0] | (s[1] << 8) : throw "len must be 2!";
                                                    ^~~~~~~~~~~~~~~~

Live Demo

答案 2 :(得分:-1)

遗憾的是,这不适用于发表评论。

修复了使ungood文字成为编译时错误:

  • 已修改签名值的移位。
  • 使用不带参数的throw
  • 明确假设8位字节。
#include <iostream>
#include <stdint.h>
#include <limits.h>         // CHAR_BIT
using namespace std;

using Byte = unsigned char;
const int bits_per_byte = CHAR_BIT;

static_assert( bits_per_byte == 8, "!" );

constexpr auto operator "" _int( char const* s, std::size_t len )
    -> uint16_t 
{ return len == 2 ? Byte( s[0] ) | (Byte( s[1] ) << 8u) : throw "Bah!"; }

#define CHAR_PAIR( s ) static_cast<uint16_t>( sizeof( char[s ## _int] ) )

auto main()
    -> int
{
    CHAR_PAIR( "AB" );              // OK
    CHAR_PAIR( "ABC" );             //! Doesn't compile as ISO C++.
}

使用Visual C ++即可满足所有需要。

g ++在这方面不太符合标准,因此对于该编译器添加选项-Werror=vla

使用g ++,您也可以使用以下宏:

#define CHAR_PAIR( s ) []() constexpr { constexpr auto r = s##_int; return r; }()

这提供了更多信息性错误消息,但Visual C ++ 2017不支持。