2011-09-30 52 views
4

我有一个类来包装字符串文字并在编译时计算大小。将传递的参数限制为字符串文字

的构造是这样的:

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字符串文字?编译时间检测是首选,但如果没有更好的方法,则运行时间是可以接受的。

+0

@Nawaz提到的问题具体是C字符串文字。我认为这是适当的提及。 – JaredPar

+0

c标签可能不合适。我们拭目以待。我希望有人会利用C++ 11的新特性('constexpr',variadics等)来获得一些技巧。 –

+0

只有在运行时才会有大小的损失?尽管如此,我会发布答案。 –

回答

8

有一种方法可以强制字符串文字参数:使用户定义的文字操作符。可以使运营商constexpr在编译时得到的大小:

constexpr Literal operator "" _suffix(char const* str, size_t len) { 
    return Literal(chars, len); 
} 

我不知道在这个时候实现此功能的任何编译器。

+0

+1为天才...和疯狂:) –

+0

这个运算符不允许''你好世界_literal',虽然:( –

+0

@ JohannesSchaub-litb哦:(你是对的,它只适用于整数和浮点文字,这是一个遗憾,我离开了答案,但它现在还不是很酷:( –

2

不,没有办法做到这一点。字符串文字有一个特定的类型,所有的方法重载解析都是在该类型上完成的,而不是它是一个字符串文字。任何接受字符串文字的方法最终都会接受任何具有相同类型的值。

如果你的函数完全依赖于作为字符串文字来运行的项目,那么你可能需要重新访问该函数。这取决于它无法保证的数据。

+0

'不,没有办法做到这一点。当然这是可能的。 – iammilind

+6

@iammilind你的方法取决于每个来电者是一个好公民。问题的全部目的是阻止人们成为坏公民。 – JaredPar

3

。您可以通过以下预处理产生编译时错误

#define IS_STRING_LITERAL(X) "" X "" 

如果您尝试通过不是字符串字面以外的任何,编译将会失败。用法:

Literal greet(IS_STRING_LITERAL("Hello World!")); // ok 
Literal greet(IS_STRING_LITERAL(broke)); // error 
+8

这个解决方案取决于每个人都是一个好公民,而这个问题的关键在于阻止人们成为坏公民。 – JaredPar

+0

'IS_STRING_LITERAL(+ 0)'。 –

+0

@ JohannesSchaub-litb,实际上,我故意把''“”X'格式(它会产生更好的编译器错误)。我认为''''''解决了这个问题。编辑 – iammilind

0

字符串文字没有单独的类型来区分它与const char数组。

然而,这会使意外传递(非const)char数组变得稍微困难​​。

#include <cstdlib> 

struct Literal 
{ 
    template< std::size_t N > 
    Literal(const char (&literal)[N]){} 

    template< std::size_t N > 
    Literal(char (&literal)[N]) = delete; 
}; 

int main() 
{ 
    Literal greet("Hello World!"); 
    char a[] = "Hello world"; 
    Literal broke(a); //fails 
} 

至于运行时检查,非文字的唯一问题是它可能不以null结尾?正如你知道数组的大小,你可以循环它(最好向后),看看它里面是否有一个\0

3

随着与constexpr充分支持一个C++编译器11,我们可以使用constexpr功能,其编译成一个非const表达体的情况下,所述后零字符条件不能满足的使用constexpr构造,使汇编失败并出现错误。下面的代码扩展UncleBens的代码,并通过an article of Andrzej's C++ blog启发:

#include <cstdlib> 

class Literal 
{ 
    public: 

    template <std::size_t N> constexpr 
    Literal(const char (&str)[N]) 
    : mStr(str), 
     mLength(checkForTrailingZeroAndGetLength(str[N - 1], N)) 
    { 
    } 

    template <std::size_t N> Literal(char (&str)[N]) = delete; 

    private: 
    const char* mStr; 
    std::size_t mLength; 

    struct Not_a_CString_Exception{}; 

    constexpr static 
    std::size_t checkForTrailingZeroAndGetLength(char ch, std::size_t sz) 
    { 
     return (ch) ? throw Not_a_CString_Exception() : (sz - 1); 
    } 
}; 

constexpr char broke[] = { 'a', 'b', 'c' }; 

//constexpr Literal lit = (broke); // causes compile time error 
constexpr Literal bla = "bla"; // constructed at compile time 

我测试此代码用gcc 4.8.2。使用MS Visual C++ 2013 CTP编译失败,因为它仍不完全支持constexprconstexpr成员函数仍不支持)。

也许我应该提到,我的第一个(首选)的方法是简单地在构造函数体插入

static_assert(str[N - 1] == '\0', "Not a C string.") 

。它没有编译错误,看起来,构造函数必须有一个空的主体。我不知道,如果这是C++ 11的限制,并且未来的标准可能会放宽。

0

我曾经想出一个C++ 98版本,它使用了类似于@ k.st提出的方法。为了完整起见,我将添加这个以解决对C++ 98宏的一些批评。 该版本试图通过阻止直接通过私有ctor构建并将唯一可访问的工厂函数移动到由“官方”创建宏使用的详细名称空间中来尝试强制执行良好行为。不完全漂亮,但更多的傻瓜证明。这样,用户必须至少明确地使用明显标记为内部的功能,如果他们想要行为不端。一如既往,没有办法防止有意的恶意。

class StringLiteral 
{ 
private: 
    // Direct usage is forbidden. Use STRING_LITERAL() macro instead. 
    friend StringLiteral detail::CreateStringLiteral(const char* str); 
    explicit StringLiteral(const char* str) : m_string(str) 
    {} 

public: 
    operator const char*() const { return m_string; } 

private: 
    const char* m_string; 
}; 

namespace detail { 

StringLiteral CreateStringLiteral(const char* str) 
{ 
    return StringLiteral(str); 
} 

} // namespace detail 

#define STRING_LITERAL_INTERNAL(a, b) detail::CreateStringLiteral(a##b) 

/** 
* \brief The only way to create a \ref StringLiteral "StringLiteral" object. 
* This will not compile if used with anything that is not a string literal. 
*/ 
#define STRING_LITERAL(str) STRING_LITERAL_INTERNAL(str, "") 
相关问题