如何在构造函数中限制字符数组的长度

4

使用扩展嵌入式C++,如何使其在发布构建中导致编译错误:

Param okParam("Yeah!"); // this line should be ok
Param nOkParam("REEEEEEEEEEE"); // too big array, not ok. compiler error.

定义:

int const c_max = 10;

template<int N>
struct Param
{
  char value[c_max];

  Param(char const (&p_value)[N])
  {
     memcpy(value, p_value, sizeof(p_value));
  }
};

我认为你无法模板化构造函数,因此整个结构需要进行模板化,是吗?


我希望这能提供一个清晰的编译错误,以便使用者立即注意到。

我们的扩展嵌入式C ++版本不提供任何STL容器,我不确定是否可能。

我正在寻找某种方式使模板结果产生良好的编译错误。不幸的是,由于平台不支持,我也不能使用boost。


你可以使用模板构造函数,N代表任意数值,接着你可以使用static_assert。 - Matthieu Brucher
我会仔细检查一下,确保我没有使用静态断言,但我不认为这个编译器支持它。 - 0xbaadf00d
char value[c_max]; is not valid, c_max needs to be a compile time constant. Also if your compiler does not support static_assert then it can be relatively easily implemented manually. See BOOST_STATIC_ASSERT - user7860670
@VTT int const c_max = 10; 一个常量表达式。 - llllllllll
2
@liliscent的问题已经被编辑,原始版本使用非静态成员字段来保存数组大小。 - user7860670
是的,我没有记录这个更改,因为它不是这个问题的主要点。对此造成的困惑很抱歉。 - 0xbaadf00d
2个回答

4
您基本上有两种解决方案:SFINAE(C++98)或static_assert(C++11):

SFINAE

您可以为 Param 提供一个仅适用于长度小于给定大小的字符数组的构造函数。在 C++98 中,这看起来有点丑陋,但它是有效的:

#include <cstddef>

template<bool b>
struct enable_if {};

template<>
struct enable_if<true>
{
    typedef int type;
};


template<std::size_t MAXSIZE>
struct Param
{
    template<std::size_t SIZE>
    explicit Param(
        char const (&input) [SIZE],
        std::size_t = sizeof(typename enable_if<SIZE < MAXSIZE>::type) // SFINAE at work
    ) { (void) input; }
};

int main()
{
    // "hello": char const[6], 6 < 7, OK
    Param<7> p1("hello");

    // "hello world": char const[12], 12 >= 7, KO
    Param<7> p2("hello world"); // ugly error here
}

断言(仅适用于C++11)

Param的构造函数中,您可以检查所提供的字符数组是否过大,并在编译时弹出可读的错误:

现场演示

#include <cstddef>
#include <type_traits>

template<std::size_t MAXSIZE>
struct Param
{
    template<std::size_t SIZE>
    explicit Param(char const (&input) [SIZE])
    { static_assert(sizeof(input) < MAXSIZE, "input is too big."); }
};

int main()
{
    // "hello": char const[6], 6 < 7, OK
    Param<7> p1("hello");

    // "hello world": char const[12], 12 >= 7, KO
    Param<7> p2("hello world"); // "error: static assertion failed: input is too big."
}

Live demo


2
不幸的是,OP 无法使用 static_assert() 或 C++11 的改进。 - max66
有没有想法自己编写 std::enable_if_t? - 0xbaadf00d
我感到很愚蠢,没有意识到现在该怎么做...好吧,活着就是学习。谢谢!+1 - 0xbaadf00d

3

可能最简单的方法是添加一个static_assert,如果您的实现还没有static_assert,则可以使用旧的C技术进行编译时检查之一:

#include <cstring>

#if __cplusplus < 201103L
#define static_assert(expr, message)                                    \
    int static_assert_(int (&static_assert_failed)[(expr)?1:-1])
#endif

template<int N>
struct Param
{
    static const int c_max = 10;
    static_assert(N < c_max, "Param string too long");
    char value[c_max];

    Param(char const (&p_value)[N])
    {
        std::memcpy(value, p_value, sizeof p_value);
    }
};

int main()
{
    Param okParam("Yeah!"); // this line should be ok
    Param nOkParam("REEEEEEEEEEE"); // too big array, not ok. compiler error.
}

没有 eecpp 的标签,也不是 c++98。虽然我在第一句话中提到了这个关键信息。 - 0xbaadf00d
不错。如果我想支持大小为1的数组,应该是[(expr)?0:-1]。 - 0xbaadf00d
@0xbaadf00d,不是为了在expr为假时生成错误(请记住,在这种情况下,expr扩展为N < c_max)。一些编译器允许使用零大小的数组(作为非标准扩展),因此使用负值触发故障更加健壮。 - Toby Speight
对不起,我看错了,是的。你正在创建一个数组。我误读了错误是如何生成的。我现在明白了。 - 0xbaadf00d
实际上,它声明了一个函数,该函数以(有效或错误的)数组引用作为参数。 - Toby Speight

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接