我想添加編譯時檢查double
的不同含義。在現實世界中,我試圖確保所有計算都以一致的單位完成。爲了這個問題的目的,我編制了一個玩具的例子,其中數字有味道。如何防止模板化別名的隱式保留值轉換?
我一直在嘗試基於模板參數來實現此目的。使用C++ 0x中的別名功能在another answer描述,我宣佈一個Number<Flavor>
爲:
enum Flavor { Cherry, Plum, Raspberry };
template <Flavor> using Number = double;
這讓我聲明局部變量或參數數目的特定口味,然後使用這些變量作爲普通雙打的能力大多數情況下。
我的問題是,我無法找到一個方法來聲明一個函數,只接受特定的香味作爲它的參數:
void printCherryNumber(Number<Cherry> num) { cout << num << endl; }
int main() {
Number<Cherry> a(5);
Number<Plum> b(6);
Number<Raspberry> c(3.1415);
printCherryNumber(a);
printCherryNumber(b); // O, if only this could be a compiler error.
return 0;
}
我的目標是讓printCherryNumber(b)
無法編譯,因爲b
是Number<Plum>
不是Number<Cherry>
。許多現有的問題解決方案似乎不適用於我用於Number
的類型別名構造。
的東西,我已經試過
從this answer,我看到的建議,添加明確不做任何事或斷功能的模板化版本,如
template <typename T> void printCherryNumber(T num) = delete;
,沒有任何效果可言,爲什麼它呢? Number<Plum>
確實是double
和Number<Cherry>
也是double
所以編譯器從不打擾模板版本。
Another answer建議使用一個模板函數,靜態斷言,如:
template <Flavor F> void printPlumNumber(Number<F> num) {
static_assert(F == Plum, "Wrong number flavor!");
cout << num << endl;
}
失敗的原因是無論F
的實際價值,Number<F>
仍然只是double
,所以我得到一個錯誤有關不能夠推斷出F
的值。
在別處有人suggests explicit specialization,這也沒有這種情況:
template <Flavor F> void printRaspberryNumber(Number<F> num) = delete;
template <> void printRaspberryNumber<Raspberry>(Number<Raspberry> num) {
cout << num << endl;
}
這裏,編譯器將調用模棱兩可,部分也是因爲它不能爲F
推斷值。
大象在房間
我當然可以,讓Number
在
template <Flavor> struct Number { double value; };
形式的單個價值結構,但我想避免這個選項,因爲我不是在我的代碼中到處都有.value
的想法讓我非常興奮,我也不是特別渴望定義運營商爲Number
,只是代理服務器翻倍。