![](/img/trans.png)
[英]Strange compile error when calling explicitly specialized class member template function
[英]Force compile time error when specialized template function is invoked
我有一個模板功能。 只要參數不是指針類型,它就具有良好定義的語義。 如果有人調用此函數傳遞類型指針的參數,我想強制編譯時錯誤。 我編寫通用(合法)模板和相應的部分專用(非法)版本沒有問題。 我只是想不出如何將錯誤從函數定義推遲到函數調用。
使用C ++ 0x :(在http://ideone.com/ZMNb1上查看)
#include <type_traits>
#include <iostream>
template <typename T>
void cannot_take_pointer(T ptr)
{
static_assert(!std::is_pointer<T>::value,
"cannot_take_pointer requires non-pointer argument");
std::cout << "ok\n";
}
int main()
{
int x;
cannot_take_pointer(x);
cannot_take_pointer(&x); // fails to compile
}
實際上,你不需要專門化它。 只需在函數體中添加:
BOOST_STATIC_ASSERT(!boost::is_pointer<T>()::value);
這將導致失敗,這應該是相當容易理解的。
如果你想自己這樣做(而不是使用像BOOST_STATIC _ASSERT這樣的東西),通常會涉及兩到三個基本技巧。
第一個(也可能是最重要的,在你的情況下)是使用sizeof
(通常將結果轉換為void
)來編譯一些代碼而不產生任何將在編譯時執行的代碼。
第二是產生一些在適當的情況下非法的代碼。 一種典型的方法是創建一個大小等於某個表達式值的數組。 如果表達式的值為0,則數組的大小為0,這是不允許的。 或者,如果大小為1,則合法。 它的一個問題是它產生的錯誤消息通常是毫無意義的 - 很難猜測“錯誤:數組必須具有正大小”(或類似的東西)與“模板參數不能是指針”有關。
要生成更有意義的錯誤消息,通常使用稍微不同的技巧。 在這種情況下,從一個類轉換到另一個類,如果表達式為false,則會失敗,但如果是真的則會成功。 一種方法是這樣的:
template <bool>
struct check { check(...); };
template <>
class check<false> {};
check(...);
意味着任何其他類型都可以(理論上)轉換為check<true>
(但請注意,我們只聲明函數,永遠不要定義它,所以如果你試圖執行這樣的代碼,它就不會鏈接)。 check<false>
缺少任何轉換構造函數意味着嘗試將其他任何內容轉換為check<false>
將始終失敗。
然后我們可以使用像這樣的宏:
#define STATIC_ASSERT(expr, msg) { \
struct Error_##msg {}; \
(void)sizeof(check<(expr)!=0>((Error_##msg))); \
}
你可以使用這樣的東西: STATIC_ASSERT(whatever, parameter_cannot_be_a_pointer);
。 這將擴展到如下:
struct Error_parameter_cannot_be_a_pointer {};
(void)sizeof(check<(expr)!=0>(Error_parameter_cannot_be_a_pointer);
然后,如果expr
!= 0,它將嘗試將Error_parameter_cannot_be_a_pointer轉換為check<true>
,這將成功。
在另一方面,如果expr
不等於0時,它會嘗試轉換到一個check<false>
,這將失敗。 我們至少希望當發生這種情況時,我們會收到類似這樣的錯誤消息:
error cannot convert:
Error_parameter_cannot_be_a_pointer
to
check<false>
顯然,如果可以的話 ,我們希望得到更好的信息,但即便如此,這也不是太可怕。 您只需忽略“包裝”,並查看源類型的名稱以便很好地了解問題。
聽起來像是boost::disable_if
的完美案例。 這樣的事情應該有效。
template <class T>
void func(T x, typename boost::disable_if<boost::is_pointer<T> >::type* dummy = 0) {
std::cout << x << std::endl;
}
func(10); // works
func(std::string("hello")); // works
func("hello world"); // error: no matching function for call to 'func(const char [6])'
func(new int(10)); // error: no matching function for call to 'func(int*&)'
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.