[英]Detect compile-time literals and constants
假設我想編寫一個通用類,它維護一個始終保持在兩個值之間的整數。 像這樣的東西:
template<int Lower, int Upper>
class MyInt {
private:
int m_int;
public:
// Constructors, operators...
};
類不變量是Lower <= m_int <= Upper
。 當然,MyInt應該具有整數所有的常用操作,比如賦值和算術運算符。 如果操作將其置於打破其不變量的狀態,MyInt將拋出。 但是,在許多情況下,這應該是編譯時可檢測的。 考慮這個示例代碼:
int foo = 500;
constexpr int const bar = 500;
MyInt<0,100> a = 15; // OK
MyInt<0,100> b = foo; // Throws at runtime
MyInt<0,100> c = 500; // Compile error?
MyInt<0,100> d = bar; // Compile error?
MyInt<0,100> f = std::integral_constant<int, 500>; // Compile error
對於std::integral_constant
,編寫適當的構造函數是直截了當的。 但是有可能編譯時檢測a
在范圍內而c
和d
不是嗎? 指定的值是編譯時已知的文字或constexpr常量。
我已經嘗試了SFINAE-ing around和whatnot,但我找不到從值語義到模板參數的方法,即使對於這些情況,我聲稱這些值顯然是編譯時常量。
對於C ++ 17來說,語言是否真的沒有提供實現它所需的工具? 如果是的話,即將推出的C ++ 20會改變嗎? 如果我正在尋找的是不可能的,這是什么原因? 我的興趣完全是教育性的,所以如果我遺漏某些東西(比如文字實際上不是編譯時常量或其他東西),我會感興趣。
注意:我知道通過引入自定義文字后綴並要求用戶輸入如下內容,可以減少案例f
難度:
MyInt<0,100> g = 15_constint; // OK
MyInt<0,100> h = 500_constint; // Compile error
我也知道有可能提供這樣的界面:
MyInt<0,100> i;
i.assign<500>(); // Compile error
然而,這兩種解決方法都帶有一定的打字開銷,並不一定是慣用的C ++。
如果我正在尋找的是不可能的,這是什么原因?
基本上,它歸結為C ++函數模型不允許函數識別constexpr
參數和運行時參數之間的區別。 如果一個函數接受一個int
,那么它需要一個int
。 根據int
是由常量表達式(如文字)還是運行時值提供,該函數的行為不能有所不同。
即使對於constexpr
功能 ,這也是如此。 你不能有一個constexpr
函數,它可以對其參數進行編譯時檢查。 評估可以在編譯時完成,但是要做foo(500);
最終必須與auto b = 500; foo(b);
auto b = 500; foo(b);
。
這就是為什么變通方法都涉及使用技巧將常量表達式放在模板參數中,這種識別是可能的。 當然,模板參數永遠不能是運行時值,因此會產生其他問題(例如必須具有多個函數)。 作為一個模板參數是一個通常很痛苦的事情。
基本上,你想要的是一個函數可以聲明一個參數是constexpr
(以及重載規則,以允許你有一個非constexpr
版本)。 沒有這樣的提案被投票到C ++ 20中。 最好的是P1045 ,委員會尚未討論過,並且還有一堆需要填補的漏洞。所以我不會屏住呼吸。
試試這個吧。 這個例子非常簡單:
template<int Max, int Min>
class MyInt
{
public:
constexpr MyInt(int i) : m_int(i > Max ? throw std::exception("out of bouonds int") : ( i < Min ? throw std::exception("out of bouonds int") : i)) {}
private:
int m_int;
};
int main()
{
MyInt<1, 2> i(4);
}
它顯示編譯時錯誤:)。 我使用這個SO問題作為指導: constexpr構造函數與編譯時驗證
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.