【问题标题】:How to limit char array length in constructor如何在构造函数中限制字符数组长度
【发布时间】:2018-11-30 10:52:27
【问题描述】:

使用扩展的嵌入式 Cpp。如何在发布版本中导致编译错误:

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 模板化 cosntructor,然后你可以使用 static_assert。
  • 我会仔细检查我没有静态断言,但我认为这个编译器不支持它。
  • char value[c_max]; 无效,c_max 需要是编译时间常数。此外,如果您的编译器不支持static_assert,那么它可以相对容易地手动实现。见BOOST_STATIC_ASSERT
  • @VTT int const c_max = 10; 一个常量表达式。
  • @liliscent 问题已编辑,原始版本使用非静态成员字段来保存数组大小。

标签: c++ templates c++98


【解决方案1】:

您基本上有两种解决方案: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
}

Live demo

断言(仅限 C++11)

Param的构造函数中,你可以检查提供的char数组是否太大,并在编译时弹出可读错误:

#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

【讨论】:

  • 很遗憾,OP 不能使用 static_assert() 或 C++11 改进
  • 知道如何自己编写 std::enable_if_t 吗?
  • 我觉得很愚蠢,因为现在没有意识到如何制作它......好吧。活到老,学到老。谢谢! +1
【解决方案2】:

可能最简单的方法是添加static_assert,如果您的实现还没有static_assert,则使用the old C techniques for compile-time checks 之一:

#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。不过,我在第一句话中就告诉了这个关键信息。
  • 不错。应该是 [(expr)?0:-1]) 如果我想支持大小为 1 的数组。
  • @0xbaadf00d, 否:当expr 为假时会产生错误(请记住,在这种情况下,expr 扩展为 N &lt; c_max)。一些编译器允许大小为零的数组(作为非标准扩展),因此使用负值来触发失败更加稳健。
  • 对,我看错了,是的。您正在那里创建一个数组。我误读了错误是如何产生的。我现在看到了。
  • 实际上,它声明了一个函数,它接受一个(有效或错误的)数组引用作为参数。
猜你喜欢
  • 1970-01-01
  • 2015-06-24
  • 2015-08-18
  • 1970-01-01
  • 2013-07-05
  • 1970-01-01
  • 2013-03-04
  • 2015-06-04
  • 2014-11-21
相关资源
最近更新 更多