你可以舉一個例子,其中static_assert(...) 'C++0x'
將優雅地解決手中的問題?static_assert是做什麼的,你會用它做什麼?
我熟悉運行時間assert(...)
。我應該在什麼時候比普通assert(...)
更喜歡static_assert(...)
?
此外,在boost
有一種叫做BOOST_STATIC_ASSERT
,是否與static_assert(...)
相同?
你可以舉一個例子,其中static_assert(...) 'C++0x'
將優雅地解決手中的問題?static_assert是做什麼的,你會用它做什麼?
我熟悉運行時間assert(...)
。我應該在什麼時候比普通assert(...)
更喜歡static_assert(...)
?
此外,在boost
有一種叫做BOOST_STATIC_ASSERT
,是否與static_assert(...)
相同?
關閉我的頭頂......
#include "SomeLibrary.h"
static_assert(SomeLibrary::Version > 2,
"Old versions of SomeLibrary are missing the foo functionality. Cannot proceed!");
class UsingSomeLibrary {
// ...
};
假設SomeLibrary::Version
被聲明爲靜態常量,而不是#define
d(正如人們所期望的C++庫)。
對比具有實際編譯SomeLibrary
和你的代碼,鏈接的一切,並運行可執行文件只然後地發現,你花30分鐘編譯SomeLibrary
不兼容的版本。
@Arak,以響應您的評論:是的,你可以有static_assert
只是坐在了何地,從它的外觀:
class Foo
{
public:
static const int bar = 3;
};
static_assert(Foo::bar > 4, "Foo::bar is too small :(");
int main()
{
return Foo::bar;
}
$ g++ --std=c++0x a.cpp a.cpp:7: error: static assertion failed: "Foo::bar is too small :("
static_assert
的一種用法可能是確保結構(即與外部世界的接口,如網絡或文件)的大小與您的預期完全相同。這將會發現某些人在沒有意識到結果的情況下增加或修改結構中的成員的情況。 static_assert
會提取並警告用戶。
我用它來保證我對編譯器的行爲的假設,標題,庫,甚至我自己的代碼都是正確的。例如,在這裏我驗證結構已被正確打包到預期的大小。
struct LogicalBlockAddress
{
#pragma pack(push, 1)
Uint32 logicalBlockNumber;
Uint16 partitionReferenceNumber;
#pragma pack(pop)
};
BOOST_STATIC_ASSERT(sizeof(LogicalBlockAddress) == 6);
在一類包裝stdio.h
的fseek()
,我已經採取了一些快捷方式enum Origin
並檢查這些快捷鍵與stdio.h
uint64_t BasicFile::seek(int64_t offset, enum Origin origin)
{
BOOST_STATIC_ASSERT(SEEK_SET == Origin::SET);
定義的常量對準你應該更喜歡static_assert
在assert
當行爲是在編譯時定義的,而不是在運行時定義的,比如我上面給出的例子。例如,這是而不是這種情況將包括參數和返回碼檢查。
BOOST_STATIC_ASSERT
是一個預C++ 0x宏,如果條件不滿足,會生成非法代碼。意圖是相同的,儘管static_assert
是標準化的,並且可以提供更好的編譯器診斷。
靜態斷言用於在編譯時斷言。當靜態斷言失敗時,程序不會編譯。這在不同情況下非常有用,例如,如果您通過嚴格取決於具有完全32位的對象的代碼來實現某些功能。你可以把這樣的靜態斷言
static_assert(sizeof(unsigned int) * CHAR_BIT == 32);
在你的代碼。在另一個平臺上,使用不同大小的unsigned int
類型,編譯將失敗,從而引起開發人員注意代碼中有問題的部分,並建議他們重新實施或重新檢查它。
再例如,您可能希望通過一些積分值作爲void *
指向函數(一劈,但多次使用),並要確保積分值將融入指針
int i;
static_assert(sizeof(void *) >= sizeof i);
foo((void *) i);
您可能需要在該char
類型與負值簽署
static_assert(CHAR_MIN < 0);
或整數分頻的資產將向零舍
static_assert(-5/2 == -2);
依此類推。
許多情況下的運行時斷言可以用來代替靜態斷言,但運行時斷言僅在運行時纔有效,並且只有當控制權通過斷言時纔有效。由於這個原因,一個失敗的運行時斷言可能處於休眠狀態,在很長一段時間內未被檢測到。
當然,靜態斷言中的表達式必須是編譯時常量。它不能是運行時間值。對於運行時間值,您別無選擇,只能使用普通的assert
。
BOOST_STATIC_ASSERT
是static_assert
功能的跨平臺包裝。
目前,我正在使用static_assert爲了對類實施「概念」。
例如:
template <typename T, typename U>
struct Type
{
BOOST_STATIC_ASSERT(boost::is_base_of<T, Interface>::value);
BOOST_STATIC_ASSERT(std::numeric_limits<U>::is_integer);
/* ... more code ... */
};
這將導致一個編譯時間錯誤,如果上述任何條件都不滿足。
既然C++ 11已經出來(並且已經出來了一段時間),static_assert應該被所有主要編譯器的更新版本所支持。 對於那些不能等待C++ 14(希望包含模板約束)的人來說,這是一個非常有用的static_assert應用程序。 – Collin
這並不直接回答原始問題,但對如何在C++ 11之前執行這些編譯時檢查進行了有趣的研究。
第2章(第2.1節)的Modern C++ Design安德烈Alexanderscu實現))這一想法編譯時斷言的這樣
template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};
#define STATIC_CHECK(expr, msg) \
{ CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }
比較宏STATIC_CHECK(和static_assert(
STATIC_CHECK(0, COMPILATION_FAILED);
static_assert(0, "compilation failed");
在如果沒有概念,可以使用static_assert
進行簡單和可讀的編譯時類型檢查,例如,在模板中:
template <class T>
void MyFunc(T value)
{
static_assert(std::is_base_of<MyBase, T>::value,
"T must be derived from MyBase");
// ...
}
還請參見:BOOST_MPL_ASSERT,BOOST_MPL_ASSERT_NOT,BOOST_MPL_ASSERT_MSG,BOOST_MPL_ASSERT_RELATION [http://www.boost.org/doc/libs/1_40_0/libs/mpl/doc/refmanual/asserts.html]以獲取更多選項。 _MSG特別好,一旦你找出如何使用它。 – KitsuneYMG