2012-12-13 16 views
7

更新:我下面貼 我自己的答案,並有此事更長的版本在這裏:http://scrupulousabstractions.tumblr.com/post/38460349771/c-11-type-safe-use-of-integer-user-defined-literals編譯時類型轉換檢查(constexpr和用戶定義的文字)

問:

我我做了一個簡單的constexpr用戶定義文字_X,它獲得了一個無符號長long值(這就是數字用戶定義的文字的工作方式:http://en.cppreference.com/w/cpp/language/user_literal),然後我確定該值符合簽名long long。

這一切運作良好(過大的值會導致編譯錯誤),但只有當我明確地創建一個變量如

constexpr auto a= 150_X; 

如果不是我寫的東西典型的像

cout << 150_X << endl;; 

測試不在編譯時執行。

  • constexpr函數是否只在編譯時執行,如果它們被分配給constexpr變量? (我無法在標準中找到)

  • 是否有可能實現我正在尋找的_X的安全行爲?

完整的示例:

#include<iostream> 
#include<stdexcept> 

inline constexpr long long testConv(unsigned long long v) { 
    return (v > 100) ? throw std::exception() : v; 
} // will eventually use actual limit from numeric_limits 

inline constexpr long long operator "" _X(unsigned long long f) { 
    return testConv(f) ; 
} 

int main(){ 
    constexpr auto a= 5_X; 
    std::cout << a << std::endl; 
    std::cout << 200_X << std::endl; // This bad literal is accepted at compile time 
    constexpr auto c=250_X;   // This bad literal is not accepted at compile time 
    std::cout << c << std::endl; 
} 

哦,供參考:我用gcc4.7.2。

回答

4

自我回答: 我發現了一個完整的解決方案,通過評論和其他答案我的問題,以及其他問題,如https://stackoverflow.com/a/13384317/1149664啓發。

的解決方案是由10

我這裏寫這篇自我回答的詳細版本使用用戶定義文字的模板形式和手動總結數量的基礎上,已經被解析數字的總和乘以:http://scrupulousabstractions.tumblr.com/post/38460349771/c-11-type-safe-use-of-integer-user-defined-literals

template<char... Chars> 
int operator"" _steps(){ 
    return {litparser<0,Chars...>::value}; 
} 

Litparser有點模板元編程這需要從由字符數參數包中保持的輸入字符擴展參數字符的列表。

typedef unsigned long long ULL; 

// Delcare the litparser 
template<ULL Sum, char... Chars> struct litparser; 

// Specialize on the case where there's at least one character left: 
template<ULL Sum, char Head, char... Rest> 
struct litparser<Sum, Head, Rest...> { 
// parse a digit. recurse with new sum and ramaining digits 
    static const ULL value = litparser< 
    (Head <'0' || Head >'9') ? throw std::exception() : 
    Sum*10 + Head-'0' , Rest...>::value; 
}; 

// When 'Rest' finally is empty, we reach this terminating case 
template<ULL Sum> struct litparser<Sum> { 
    static const ULL value = Sum; 
}; 
+0

很好的答案,並且感謝您的延長寫作!很有幫助。 – U007D

+0

這當然只有在文字不是八進制或十六進制時纔有效。在這些情況下,將需要不同的文字分析器。 – nshct

3

constexpr函數可能是在編譯時執行;也就是說,它們是合格的用於常量表達式中。如果它們沒有用於常量表達式,那麼在編譯時就沒有必要執行它們,儘管我認爲它是允許的。因爲你不允許聲明一個參數爲constexpr(7.1.5/1節)[1],所以我不認爲在編譯時有什麼辦法可以強制operator "" _X(unsigned long long)的評估,但你可能與template<char...> operator "" _X()

如果在常量表達式中調用constexpr函數,參數將是一個常量表達式(如果不是,則該調用不是常量表達式)。但是,您不能強制呼叫是一個常量表達式,因爲您不允許聲明參數constexpr,請參閱參考標準,因爲聲明參數constexpr,因此該呼叫是常量表達式。


[注1]:感謝@LightnessRacesInOrbit用於搜索的標準來證明在第二段的要求。

+0

'因爲你不允許聲明一個參數爲constexpr'嗯,真的嗎? –

+1

嗯是真的(7.1.5/1) - 但是當被稱爲常量表達式的一部分時,「constexpr」要求是從被調用的函數「繼承」的 –

+0

@LightnessRacesinOrbit:如果函數被稱爲常量表達式的一部分。你不能用'constexpr'參數來寫函數,以堅持它是常量表達式的一部分。那不清楚嗎? – rici

1

Constexpr函數不需要在編譯時執行。但是你的目標可以實現。爲了更好地理解問題,以及如何創建一個始終在編譯時評估的迭代的示例,我推薦使用this post

+0

謝謝,當您寫這篇文章時,我已經發布了我的答案。模板和手動解析就是......爲你的好博客(我已經遵循)的方式。 –

相關問題