2

我想玩編譯時在C++編譯器中合成常量字符串哈希值的奇特遊戲。這可以讓我用一個標識符替換字符串,大大節省了代碼的大小和複雜性。是一個編譯時常量索引編譯時常量數組本身編譯時常量?

爲了編程的清晰和簡單,如果我可以在編譯時使用簡單的內聯字符串(如「Hello」,它們是編譯時常量指針指向編譯時常量字符)進行檢查和計算,那將非常棒。

如果我可以在編譯時編入索引,我可以創建一個模板元程序來執行我想要的操作。但目前還不清楚C++標準本身是否將ct常數數組的ct常數索引視爲ct常數。

問另一種方式,

const char v="Hello"[0]; 

是相當有效的C++(和C)。但是是一個編譯時間常量的值嗎?

我已經相信答案是否定的,但實際上一些編譯器接受它,甚至沒有任何警告,更少的錯誤。例如,從英特爾C++編譯器下面的編譯和運行,甚至沒有一個警告:

#include <iostream> 
const char value="Hello"[0]; 
template<char c> void printMe() 
{ 
    std::cout << "Template Val=" << c << std::endl; 
} 

int main() 
{ 
    const char v='H'; 
    printMe<'H'>(); 
    printMe<v>(); 
    printMe<value>(); // The tricky and interesting case! 
} 

然而,微軟的編譯器將不能編譯,提供有關使用模板與內部對象的合理連貫的錯誤信息連鎖。

我懷疑我的問題的答案是「不,你不能假定任何數組引用,即使是在編譯時常量索引常量的常量數組」。這是否意味着英特爾編譯器的成功執行是英特爾編譯器中的一個錯誤?

回答

2

它在GCC上也不起作用。

但是,在語言兼容性觀點之外,編譯器優化器確實把它當作字符常量處理,這非常好。我利用這個事實來允許預處理器生成的字符常量(使用*#foo)。見文件hdr.h中的http://cvs.openbsd.org/cgi-bin/query-pr-wrapper?full=yes&numbers=1652。隨着宏觀,你可以寫

DECR(h, e, l, l, o) 

而不是

DECR('h', 'e', 'l', 'l', 'o') 

更可讀的,在我看來。 :-)

+0

聰明的黑客宏使用stringize宏觀操作者特性化原料字符!當然,這對嘗試使用模板參數沒有多大幫助。除非可變參數樣式的宏(C99 ??)可以去掉一個char,否則建立一個新的typedef並將其餘的var參數包含爲遞歸類型a-la Loki? – SPWorley 2009-04-20 08:00:17

1

好問題,是可以做到這一點,它的標準罰款,它會在微軟,GCC和英特爾合作,問題是你有語法錯誤:)

一第二我會做一個樣本... 好的,在這裏。這個示例是有效的C++,我經常使用它,但實際上大多數程序員不知道如何正確使用它。

template<char* MSG> 
class PrintMe 
{ 
public: 
    void operator()() 
    { 
     printf(MSG); 
    } 
}; 

char MyMessage[6] = "Hello"; //you can't use a char*, but a char array is statically safe and determined at compiletime 

int main(int argc, char* argv[]) 
{ 
    PrintMe<MyMessage> printer; 
    printer(); 
    return 0; 
} 
+1

這不是在編譯時訪問數據,只是字符指針。例如,在打印機()之後;調用你可以添加MyMessage [0] ++;打印機();你會看到數據更新。這意味着數據正在運行時被訪問,而不是編譯時。但是你的例子仍然很有趣,因爲一個非常量指針可以作爲模板參數傳遞......本身就讓人驚訝! – SPWorley 2009-04-20 07:56:09

+0

這意味着我不確定你想要做什麼,但是如果我可以做到上述,你可以做你想做的事,你能更好地解釋你最後一個模板的預期行爲是什麼? – 2009-04-20 08:14:32

0

這裏的相關差異是「積分常量表達式」和單純的編譯時常量之間的差異。 「3.0」是編譯時常量。 「int(3.0)」也是編譯時常量。但只有「3」是ICE。 [見5。19

More details at boost.org

相關問題