在C++1y
,我可以有一個引用類綁定到字符串文字,但不是char*
或char[]&
或類似?字符串字面引用類
class LitRf{
const char* data_;
size_t size_;
public:
LitRf(const char* /*?*/ s) : data_{s},size_{sizeof(s)} { /*?*/ }
};
在C++1y
,我可以有一個引用類綁定到字符串文字,但不是char*
或char[]&
或類似?字符串字面引用類
class LitRf{
const char* data_;
size_t size_;
public:
LitRf(const char* /*?*/ s) : data_{s},size_{sizeof(s)} { /*?*/ }
};
我猜你可以做的最好的是使用const char (&s)[N]
(與template<size_t N>
)作爲參數類型。但它也綁定到除字符串字面以外的任何const char數組。
添加已刪除的非常量字符數組構造函數,以禁止用非常量數組調用它。
class LitRf
{
const char* data_;
Sz size_;
public:
template<size_t N>
LitRf(char const (&s)[N])
: data_{s}, size_{N}
{}
template<size_t N>
LitRf(char (&s)[N]) = delete;
};
除此之外,你可以使用宏包裝,其(在構造函數中從未離開使用)使得它只能從文字構造一個對象,即使不是通過一個變量。
#define MakeLitRf(s) LitRf(s "")
的想法是連接兩個字符串文字,其中第二個是隻是一個空字符串。這隻有在第一個也是字符串文字的情況下才有可能;把一個變量存在語法錯誤。宏展開後,編譯器會看到類似於LitRf("foo" "")
的內容,相當於LitRf("foo")
。一些例子:
auto x = MakeLitRf("foo"); // works
const char *foo = "foo";
auto x = MakeLitRf(foo); // fails
auto x = LitRf(foo); // works, but we want it to fail...
在過去的情況下,用戶無意間(?或故意)沒有使用宏,使我們的工作一文不值。爲了使其失敗過,一個隱藏的參數添加到構造函數,這是需要添加時直接調用(和宏的定義,當然):
class LitRf
{
const char* data_;
Sz size_;
public:
// Called by the macro MakeLitRf. Unlikely to be called directly unless the user knows what he's doing.
LitRf(const char *s, void *)
: data_{s}, size_{N}
{}
// Called without macro! Throw a compiler error, explaining what's wrong.
LitRf(const char *s)
{
static_assert(false, "Please use the macro `MakeLitRf` with a string literal to construct a `LitRf`.");
}
};
#define MakeLitRf(s) LitRf(s "", nullptr)
class LitRf{
const char* data_;
Sz size_;
public:
LitRf(const char* /*?*/ s) : data_{s},size_{sizeof(s)} { /*?*/ }
LitRf(char*) = delete;
};
C++ 11除去的唯一正式的方式來檢測一個字符串作爲這樣,經由其隱式轉換的指針的非const即。
無論如何,使用這個小竅門必須使用一個宏。
在C++ 11和更高版本中,您可以做的最好的事情是建立一個強大的約定,const
數組字符類型是一個文字。
即,你的榜樣,
class LitRf
{
private:
const char* data_;
Sz size_;
template< size_t n >
LitRf(char (&)[n]) = delete;
public:
template< size_t n >
LitRf(char const (&s)[n])
: data_{s}, size_{sizeof(s) - 1}
{}
};
注意使用size_t
,而不是一個可能帶有符號的類型Sz
。這確保代碼將用g ++編譯。不幸的是,編譯器或者其舊版本的編譯器在size_t
上存在一個錯誤,或者拒絕接受代碼。
我能想出的最好的是提供一個模板化的重載static_asserts,或者使用explicit關鍵字。 – Borgleader
@Borgleader但我不認爲有一種方法來區分字符串文字和常量字符數組。 – HolyBlackCat
@Borgleader你會如何'static_assert'的東西是一個字符串文字? 「明確的」在這裏有什麼幫助?實際上,如果你可以通過'static_assert'指明某個字符串是什麼東西,那麼你也可以在SFINAE中使用相同的條件來控制重載決議,而不是綁定到函數中。 – 5gon12eder