2011-09-30 54 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, "") 
相關問題