2017-10-16 59 views
4

在下面的示例中main可以static_assert如果字符串文字以'v'開頭,但verify不能。如何靜態斷言constexpr函數內的字符串文字的條件?

爲什麼會發生?有沒有一種方法允許verifystatic_assert條件字符串中的字符?

#include <cstddef> 

template <std::size_t N> 
constexpr char get_first(const char (&str)[N]) 
{ 
    static_assert(N>1, "must be > 1"); 
    return str[0]; 
} 

template <std::size_t N> 
constexpr void verify(const char (&str)[N]) 
{ 
    static_assert(str[0] == 'v', "must start from v"); 
} 

int main() 
{ 
    static_assert(get_first("value") == 'v', "first must be 'v'"); // succeeds 
    verify("value"); // fails to compile 
} 

編譯錯誤:

main.cpp: In instantiation of 'constexpr void verify(const char (&)[N]) [with long unsigned int N = 6]': 
main.cpp:19:15: required from here 
main.cpp:13:9: error: non-constant condition for static assertion 
     static_assert(str[0] == 'v', "must start from v"); 
     ^~~~~~~~~~~~~ 
main.cpp:13:9: error: 'str' is not a constant expression 

Example

+0

如果你想有一個字符串參數,你可以編譯時斷言,我建議花。 – chris

回答

1

的問題是,verify()

template <std::size_t N> 
constexpr void verify(const char (&str)[N]) 
{ 
    static_assert(str[0] == 'v', "must start from v"); 
} 

可以稱爲編譯時運行時間。

所以錯誤,因爲可以執行static_assert(),在str,調用時編譯時間,但不能叫時運行時(當str的第一個字符是不知道編譯時)。

- 編輯 -

的OP要求在字符串文字編譯時檢查。

下面是一個愚蠢的例子,我想是不是真的有用,但我希望能有所啓發

template <char const * const str> 
constexpr bool startWithUpperLetter() 
{ 
    static_assert(str[0] != 'v', "no start with \'v\', please"); 

    return (str[0] >= 'A') && (str[0] <= 'Z'); 
} 

constexpr char const str1[] { "ABC" }; 
constexpr char const str2[] { "abc" }; 
constexpr char const str3[] { "vwx" }; 

int main() 
{ 
    static_assert(startWithUpperLetter<str1>() == true, "!"); 
    static_assert(startWithUpperLetter<str2>() == false, "!"); 
    // static_assert(startWithUpperLetter<str3>() == false, "!"); // error 
} 
+0

是否有任何語言規則使得函數或函數調用的運行時間比我們想象的要少,或編譯時間少於我們想象的? –

+0

@NickyC - 不確定要理解你的問題,但是......沒有'constexpr',函數只是(理想的)運行時; 'constexpr'是運行時**和**編譯時啓用的,我不知道一種強制編譯時啓用的方法;如果你想要的東西只能在編譯時工作,我想你必須使用模板元編程。 – max66

+0

@ max66有沒有辦法強制在編譯時發生'verify'的評估,以便我可以'static_assert'在那裏?有沒有辦法用模板元編程來分析字符串文字中的字符? –

2

我有另一種解決辦法給你。這不會使用static_assert,但保證在編譯時強制執行條件。

#include <type_traits> 
template<bool b> 
using enforce = std::bool_constant<b>; 

template <std::size_t N> 
constexpr int verify(const char (&str)[N]) 
{ 
    if(get_first(str) != 'v') { 
     throw "must start from v"; 
    } 
    return 0; 
} 

int main() 
{ 
    using assertion = enforce<verify("value")>; // compiles 
    using assertion = enforce<verify("fail")>; // fails to compile 
    // or use it like 
    constexpr auto assertion0 = verify("value"); // compiles 
} 

這使用throwing在constexpr上下文中無效。您會收到錯誤看起來somethign像這樣:

26 : <source>:26:31: error: non-type template argument is not a constant expression 
    using assertion = enforce<verify("fail")>; // fails to compile 
           ^~~~~~~~~~~~~~ 
15 : <source>:15:9: note: subexpression not valid in a constant expression 
     throw "must start from v"; 
     ^
26 : <source>:26:31: note: in call to 'verify("fail")' 
    using assertion = enforce<verify("fail")>; // fails to compile 

我們可以使用它作爲一個模板參數執行的verify constexpr評價。這也是聲明一個非void返回類型的原因。

+2

另一種方法是將'verify()'的值存儲在'constexpr'值中;例如:'constexpr int vr0 = verify(「value」); constexpr int vr1 = verify(「fail」);';在這種情況下,不需要「強制執行」 – max66

3

在C++ 17中,可以將值包裝在一個constexpr lambda(online demo)中。呼叫看起來像

verify([=] { return "value"; }); 

,並解開你可以

template <class StringWrapper> 
constexpr void verify(StringWrapper str_w) 
{ 
    constexpr auto str = str_w(); 
    static_assert(str[0] == 'v', "must start from v"); 
} 
相關問題