2016-03-03 50 views
7

C++1y,我可以有一個引用類綁定到字符串文字,但不是char*char[]&或類似?字符串字面引用類

class LitRf{ 
    const char* data_; 
    size_t size_; 
public: 
    LitRf(const char* /*?*/ s) : data_{s},size_{sizeof(s)} { /*?*/ } 
}; 
+0

我能想出的最好的是提供一個模板化的重載static_asserts,或者使用explicit關鍵字。 – Borgleader

+0

@Borgleader但我不認爲有一種方法來區分字符串文字和常量字符數組。 – HolyBlackCat

+0

@Borgleader你會如何'static_assert'的東西是一個字符串文字? 「明確的」在這裏有什麼幫助?實際上,如果你可以通過'static_assert'指明某個字符串是什麼東西,那麼你也可以在SFINAE中使用相同的條件來控制重載決議,而不是綁定到函數中。 – 5gon12eder

回答

3

我猜你可以做的最好的是使用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) 
1
class LitRf{ 
    const char* data_; 
    Sz size_; 
public: 
    LitRf(const char* /*?*/ s) : data_{s},size_{sizeof(s)} { /*?*/ } 
    LitRf(char*) = delete; 
}; 
3

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上存在一個錯誤,或者拒絕接受代碼。

+0

謝謝。 'char const []'〜'string literal'是一個合理的折中方案。不幸的是,這也會從一個非常量字符數組中初始化。 (沒關係'Sz',我不知道它是什麼 - 我在名字空間中用它作爲'std :: size_t'的'typedef') – PSkocik

+0

但是你不能區分'const char'和'char'的'const'數組 – Barry

+0

爲什麼'sizeof(s) - 1'?我知道,終止0,但OP本來並沒有減去。 – leemes