我知道爲什麼包括警衛存在,而且#pragma once
不標準,因此並不是所有的編譯器等支持有什麼情況下你不想包括警衛?
我的問題是一種不同的:
是否有任何合理的理由永遠沒有他們?我還沒有遇到這樣一種情況,理論上說,如果不在某個文件中提供包括守衛在內的任何其他地方,那麼將會有任何好處。有沒有人有一個沒有他們的實際好處的例子?
我問的原因 - 對我來說,他們看起來相當多餘,因爲你總是使用它們,並且#pragma once
的行爲也可以自動應用於字面上的一切。
我知道爲什麼包括警衛存在,而且#pragma once
不標準,因此並不是所有的編譯器等支持有什麼情況下你不想包括警衛?
我的問題是一種不同的:
是否有任何合理的理由永遠沒有他們?我還沒有遇到這樣一種情況,理論上說,如果不在某個文件中提供包括守衛在內的任何其他地方,那麼將會有任何好處。有沒有人有一個沒有他們的實際好處的例子?
我問的原因 - 對我來說,他們看起來相當多餘,因爲你總是使用它們,並且#pragma once
的行爲也可以自動應用於字面上的一切。
我已經看到了根據包含之前定義的宏生成代碼的頭文件。在這種情況下,有時需要將這些宏定義爲一個(一組)值,包括頭,重新定義宏並再次包含。每個看到這種情況的人都認爲它很醜並且最好避免,但有時(比如說,如果標題中的代碼是通過其他方式生成的),那麼這樣做更不容易。
除此之外,我想不出一個理由。
如果項目中有兩個標題使用相同的包含保護,例如,可能會出現問題。如果您有兩個第三方庫,並且它們都有一個使用包含防護符號(例如__CONSTANTS_H__
)的標頭,則在給定的編譯單元中,兩個標頭都不能成功使用#include
。更好的解決方案是#pragma once
,但一些較老的編譯器不支持這一點。
假設您有第三方庫,並且無法修改其代碼。現在假設包含來自該庫的文件會生成編譯器警告。您通常希望以高警告級別編譯自己的代碼,但這樣做會導致使用該庫的大量警告。您可以編寫警告disabler/enabler頭文件,然後您可以將其包裝在第三方庫中,並且應該可以多次包含它們。
另一個更復雜的種類使用的是Boost的預處理器的迭代構建體: http://www.boost.org/doc/libs/1_46_0/libs/preprocessor/doc/index.html
我不明白怎麼沒有包裝衛士包裝會有所作爲。如果你已經包含了包裝器,那麼* *包含的第三方頭文件的警告被禁用,並且第二次包含包裝器時,它將被包含守衛抓住,而不是任何東西。 – Mephane
@Mephane:這是包含特定於編譯器的警告控件編譯指示的標題,它們沒有包含警衛,也沒有包含警告的庫標題。 –
<cassert>
<assert.h>
「斷言宏根據NDEBUG的那 < ASSERT.H>包括在每個時間的當前狀態重新定義。 「
@sbi已經討論過代碼生成,所以讓我舉個例子。
說你有很多項目的枚舉,和你想生成一組函數用於它的每個元素...
一種解決方法是使用多包容伎倆。
// myenumeration.td
MY_ENUMERATION_META_FUNCTION(Item1)
MY_ENUMERATION_META_FUNCTION(Item2)
MY_ENUMERATION_META_FUNCTION(Item3)
MY_ENUMERATION_META_FUNCTION(Item4)
MY_ENUMERATION_META_FUNCTION(Item5)
那麼,人們只是用它像這樣:
#define MY_ENUMERATION_META_FUNCTION(Item_) \
case Item_: return #Item_;
char const* print(MyEnum i)
{
switch(i) {
#include "myenumeration.td"
}
__unreachable__("print");
return 0; // to shut up gcc
}
#undef MY_ENUMERATION_META_FUNCTION
這是否是好的或hackish的是你的,但很顯然它是有用的,有通過一切工具的功能,每次抓取一個新的值被添加到枚舉中。
如果您將'#define MY_ENUMERATION_META_FUNCTION'放在頂端myenumeration.td中,則可以只包含第二個文件*,並且可以包含第一個文件一次。你的例子看起來像一個任意的循環包含依賴關係,可以很容易地避免。如果我錯了,請糾正我。 – Mephane
@Mephane:我不明白怎麼會有一個循環依賴,因爲「enumeration.td」不包含任何東西......另外宏MY_ENUMERATION_META_FUNCTION並不意味着在枚舉文件中定義,因爲它會阻止它作爲一個元函數使用,所以它會有點挫敗在那裏定義它的目的。 –
現在我明白了。第二個文件不是另一個可以重複使用的代碼,但是是一個實際的實現,每個實現都可以定義它們自己的'MY_ENUMERATION_META_FUNCTION'版本。是的,它完全感覺像一個黑客。能否做這樣的事情是一個實際的好處,當然是相當主觀的,但我現在看到了這種可能性。 – Mephane
#pragma曾經存在的問題,以及它不屬於標準的原因是,它並不總是在任何地方都能正常工作。編譯器如果知道兩個文件是否是相同的文件(如果包含在不同的路徑中)如何?
想一想,如果編譯器出錯並且未包含應該包含的文件,會發生什麼情況?如果它包含一個文件兩次,它不應該發生什麼?你會如何解決這個問題?
隨着包括守衛,可能發生的最糟糕的是編譯需要更長的時間。
編輯: 看看這個線程在comp.std.C++「#pragma曾經在ISO標準嗎?」
http://groups.google.com/group/comp.std.c++/browse_thread/thread/c527240043c8df92
我遇到的FFTW庫這個特定用途(這是前一段時間,也許它現在改)。定義了許多函數,以便可以爲不同的基礎類型創建它們:in,double,float等,因此您可以根據需要定義多種類型,並重新包含該文件。但是,這是一個C庫。在C++中,我們將使用模板... –
@the_mandrill:在C++中,這實際上用於模板不適合問題的某些情況。特別是使用boost預處理器庫自動生成具有不同數量參數的相同代碼,如帶有0,1,2 ... N參數的boost :: bind。 –
@DavidRodríguez:據我所知,boost :: bind是通過爲最多9個參數提供適當的模板來實現的。編輯:好吧我找到了一個地方,在這種情況下,避免使用模板參數作爲返回值(當返回類型爲void時)的函數return x'的情況,但我一直設法通過特定的模板特化解決這些問題對於'void'類型。他們走的路線沒有包括警衛,但是爲了解決這個問題,重新定義「return」宏並不是必要的。 – Mephane