2012-12-05 83 views
8

我想寫一個C++ 11的功能,將只接受字符串文字作爲參數:只接受字符串文字的C++ 11函數?

void f(const char* s) { static_assert(s is a string literal); ... } 

即:

f("foo"); // OK 

char c = ...; 
f(&c); // ERROR: Doesn't compile 

string s = ...; 
f(s.c_str()); // ERROR: Doesn't compile 

etc 

反正是有實現這個?函數的簽名可以隨時更改,也可以使用宏或任何其他語言功能。

如果這是不可能的最接近的近似值是什麼? (用戶定義的文字可以幫助嗎?)

如果不是在GCC 4.7/Linux中有特定平臺的方式嗎?

+0

你將如何處理字符串文字,你無法處理非字符串文字?那麼如何傳遞一個使用字符串文字初始化的'const char * const'變量?或者是一個const char(&array)[]對字符串文字的引用? – hvd

+2

這是不可能的,因爲字符串文字只是'char const [N]'數組,因此與它們無法區分。 – Xeo

+0

也許使用用戶定義的字符串文字,該文字可以轉換爲具有隻讀數據的類型,該數據類型是該右值引用(因此它不能是命名變量)。目標是強制將字符串逐字輸入到調用點的代碼中,並靜態編譯到應用程序映像中。 –

回答

12

我想你會得到最接近的是這

template<int N> 
void f(const char (&str)[N]){ 
    ... 
} 

它將與文字和數組,但不是指針編譯。

+0

您可以通過巧妙使用'std :: enable_if <>'來進一步防止它與大多數非文字數組一起工作。請參閱http://stackoverflow.com/questions/14805011/how-to-detect-a-string-literal-with-type-traits,瞭解如何在enable_if中放置什麼(儘管該問題使用static_assert,但它是相同的概念)。 – wjl

3

另一種方法是讓GCC擴展在編譯時檢查你的特定函數是否只用一個文字字符串調用。

您可以使用MELT來擴展GCC。 MELT是擴展GCC編譯器的高級別領域專用語言,非常適合您想要的檢查。

基本上,你可以在GCC中添加一個新的代碼,並在MELT中傳遞代碼,它會找到每個疙瘩,這是調用你的函數並檢查參數確實是一個文字字符串。 melt-examples上的ex06示例應該會激勵您。然後訂閱[email protected]並在那裏詢問您的MELT特定問題。

當然,這不是一個萬無一失的方法:函數可以通過指針間接調用,它可以例如具有部分文字字符串,例如f("hello world I am here"+(i%4))在概念上是一個帶有一些文字字符串的調用(例如在.rodata段中),但不是在生成的代碼中,也不在g。中。

1

我用這個:

// these are used to force constant, literal strings in sqfish binding names 
// which allows to store/copy just the pointer without having to manage 
// allocations and memory copies 
struct _literalstring 
{ 
    // these functions are just for easy usage... not needed 
    // the struct can be empty 
    bool equal(_literalstring const *other) { return !strcmp((const char *)this, (const char *)other); } 
    bool equal(const char *other) { return !strcmp((const char *)this, other); } 
    const char *str(void) { return (const char *)this; } 
    bool empty(void) { return *(const char *)this == 0; } 
}; 

typedef _literalstring *LITSTR; 

constexpr LITSTR operator "" _LIT(const char *s, size_t) { 
    return (LITSTR)s; 
} 

然後你只需要聲明你的函數是這樣的:

void myFunc(LITSTR str) 
{ 
    printf("%s\n", str->str()); 
    printf("%s\n", (const char *)str); 
    const char *aVar = str->str(); 
    const char *another = (const char *)str; 
} 

你這樣稱呼它:

myFunc("some text"_LIT); 

如果你做的東西像這樣:

myFunc("some text"); 
myFunc(aTextVariable); 

你得到一個編譯器錯誤。