簡體   English   中英

調用專用模板函數時強制編譯時錯誤

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM