2013-02-11 22 views
6

如何可靠地static_assert不是字符串文字的東西?如何使用type_traits檢測字符串文字?

例如,在下面的代碼中,我試圖包裝標準的斷言宏,但是靜態地拒絕任何不是字符串文本的消息(因爲除了字符串字面值之外的任何東西都不會在運行時顯示觸發)。

#include <cassert> 
#include <string> 
#include <type_traits> 

#define my_assert(test, message)\ 
    static_assert(\ 
     (\ 
      !std::is_pointer<decltype(message)>::value &&\ 
      !std::is_array<decltype(message)>::value\ 
     ),\ 
     "literal string required"\ 
    );\ 
    assert((message, (test))); 

int main() { 
    my_assert(1 == 1, "one equals one"); 
    my_assert(1 == 2, "one equals two"); 

    { 
     const char *msg = "one equals one"; 
     //my_assert(1 == 1, msg); // triggers static_assert 
    } 

    { 
     const char msg[] = "one equals one"; 
     //my_assert(1 == 1, msg); // triggers static_assert 
    } 

    { 
     const std::string msg = "one equals one"; 
     //my_assert(1 == 1, msg.c_str()); // triggers static_assert 
    } 

    { 
     const int msg = 3; 
     my_assert(1 == 1, msg); // should trigger static_assert 
    } 
} 

正如你所看到的,測試通過由type_traits頭所提供的測試完成,並且, 大多,該代碼按預期工作(用gcc 4.7.2測試)。但是,它並不特別尋找字符串文字,因爲它只是拒絕程序員可能使用的常見事物。

對於上面的例子,我的解決方案可能已經足夠好了,但是我想在其他情況下使用這個或者類似的技術。

所以問題是,我如何可靠地使用type_traits(或另一種標準機制)對的任何 static_assert除了字符串文字?

+0

你真正想要當一個斷言失敗顯示一條消息?如果是這樣,請發表另一個問題。標準的'assert()'宏在我看來是無用的,但是真的有很好的方法來編寫你自己的,顯示一條消息和相關變量的值。 – Ali 2013-02-11 09:34:34

+0

@Ali謝謝,但我的問題與'assert()'很少有關係,除了它是證明問題答案可能有用的一個原因的激勵工具。當斷言使用gcc/libc提供的標準失敗時,我會收到一條好消息。當然有更復雜的方法來進行斷言,但這並不是我的問題的重點 - 正如我所說,我對如何檢測字符串字面值與其他事情感興趣。 (我自己的答案似乎在訣竅上非常接近。) – wjl 2013-02-12 02:18:09

+0

好吧,我雖然需要一個花哨的斷言。好吧,祝你好運! – Ali 2013-02-12 09:32:35

回答

5

這裏出現排斥任何我扔在它的最好我能得到,但仍然接受文字字符串:

#define my_assert(test, message)\ 
    static_assert(\ 
     (\ 
      std::is_convertible  <decltype(message), const char *>::value &&\ 
      !std::is_rvalue_reference <decltype(message)>::value &&\ 
      !std::is_pointer   <decltype(message)>::value &&\ 
      !std::is_array   <decltype(message)>::value &&\ 
      !std::is_class   <decltype(message)>::value\ 
     ),\ 
     "string literal required"\ 
    );\ 
    assert((message, (test))) 

我會很有興趣知道這實際上是詳盡正確,和/或是否有更簡單的方法來執行此檢測。

0

字符串常量的'decltype(「some string」)'返回「const char(&)[n]」類型。 因此,似乎有更簡潔,與the following answer比較的方法來檢測它:

template<typename T> 
struct IsStringLiteral : 
    std::is_same< 
     T, 
     std::add_lvalue_reference_t<const char[std::extent_v<std::remove_reference_t<T>>]> 
    > 
{}; 

online demo