将传递的参数限制为字符串文字
我有一个类来包装字符串文字并在编译时计算大小。
构造函数如下所示:
template< std::size_t N >
Literal( const char (&literal)[N] );
// used like this
Literal greet( "Hello World!" );
printf( "%s, length: %d", greet.c_str(), greet.size() );
但是代码有问题。下面的代码可以编译,我想让它出错。
char broke[] = { 'a', 'b', 'c' };
Literal l( broke );
有没有办法限制构造函数,使其只接受 c 字符串文字?编译时检测是首选,但如果没有更好的方法,运行时检测也是可以接受的。
I have a class to wrap string literals and calculate the size at compile time.
The constructor looks like this:
template< std::size_t N >
Literal( const char (&literal)[N] );
// used like this
Literal greet( "Hello World!" );
printf( "%s, length: %d", greet.c_str(), greet.size() );
There is problem with the code however. The following code compiles and I would like to make it an error.
char broke[] = { 'a', 'b', 'c' };
Literal l( broke );
Is there a way to restrict the constructor so that it only accepts c string literals? Compile time detection is preferred, but runtime is acceptable if there is no better way.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
有一种方法可以强制使用字符串文字参数:创建用户定义的文字运算符。您可以使运算符
constexpr
在编译时获取大小:我不知道目前有任何编译器实现此功能。
There is a way to force a string literal argument: make a user defined literal operator. You can make the operator
constexpr
to get the size at compile time:I don't know of any compiler that implements this feature at this time.
是。您可以使用以下预处理器生成编译时错误:
如果您尝试传递字符串文字以外的任何内容,则编译将失败。用法:
Yes. You can generate compile time error with following preprocessor:
If you try to pass anything other than a string literal, the compilation will fail. Usage:
借助完全支持 constexpr 的 C++11 编译器,我们可以使用 constexpr 函数来使用 constexpr 构造函数,该函数会编译为非const 表达式主体,以防尾随零字符前提条件未满足,导致编译失败并出现错误。以下代码扩展了 UncleBens 的代码,灵感来自 Andrzej 的 C++ 博客的一篇文章:
我用 gcc 4.8.2 测试了这段代码。使用 MS Visual C++ 2013 CTP 编译失败,因为它仍然不完全支持
constexpr
(仍然不支持constexpr
成员函数)。也许我应该提到,我的第一个(也是首选)方法是简单地插入
构造函数主体中。它因编译错误而失败,并且 constexpr 构造函数似乎必须有一个空主体。我不知道这是否是 C++11 的限制以及未来标准是否会放宽。
With a C++11 compiler with full support for
constexpr
we can use aconstexpr
constructor using aconstexpr
function, which compiles to a non-const expression body in case the trailing zero character precondition is not fulfilled, causing the compilation to fail with an error. The following code expands the code of UncleBens and is inspired by an article of Andrzej's C++ blog:I tested this code with gcc 4.8.2. Compilation with MS Visual C++ 2013 CTP failed, as it still does not fully support
constexpr
(constexpr
member functions still not supported).Probably I should mention, that my first (and preferred) approach was to simply insert
in the constructor body. It failed with a compilation error and it seems, that
constexpr
constructors must have an empty body. I don't know, if this is a C++11 restriction and if it might be relaxed by future standards.不,没有办法做到这一点。字符串文字具有特定类型,并且所有方法重载解析都是在该类型上完成的,而不是它是字符串文字。任何接受字符串文字的方法最终都会接受任何具有相同类型的值。
如果您的函数绝对依赖于字符串文字来运行,那么您可能需要重新访问该函数。这取决于它无法保证的数据。
No there is no way to do this. String literals have a particular type and all method overload resolution is done on that type, not that it's a string literal. Any method which accepts a string literal will end up accepting any value which has the same type.
If your function absolutely depends on an item being a string literal to function then you probably need to revisit the function. It's depending on data it can't guarantee.
字符串文字没有单独的类型来区分它与 const char 数组。
然而,这将使意外传递(非常量)字符数组变得更加困难。
至于运行时检查,非文字的唯一问题是它可能不是空终止的?当您知道数组的大小时,您可以对其进行循环(最好向后)以查看其中是否有
\0
。A string literal does not have a separate type to distinguish it from a const char array.
This, however, will make it slightly harder to accidentally pass (non-const) char arrays.
As to runtime checking, the only problem with a non-literal is that it may not be null-terminated? As you know the size of the array, you can loop over it (preferable backwards) to see if there's a
\0
in it.我曾经提出过一个 C++98 版本,它使用的方法类似于 @k.st 提出的方法。为了完整起见,我将添加此内容以解决有关 C++98 宏的一些批评。
此版本试图通过防止通过私有构造函数直接构造并将唯一可访问的工厂函数移动到详细名称空间中来强制执行良好行为,而详细名称空间又由“官方”创建宏使用。不完全漂亮,但更安全一点。这样,如果用户想要行为不当,则至少必须显式使用明显标记为内部的功能。一如既往,没有办法防止故意恶意行为。
I once came up with a C++98 version that uses an approach similar to the one proposed by @k.st. I'll add this for the sake of completeness to address some of the critique wrt the C++98 macro.
This version tries to enforce good behavior by preventing direct construction via a private ctor and moving the only accessible factory function into a detail namespace which in turn is used by the "offical" creation macro. Not exactly pretty, but a bit more fool proof. This way, users have to at least explicitly use functionality that is obviously marked as internal if they want to misbehave. As always, there is no way to protect against intentional malignity.