做不是使用enable_if
來執行您的要求。使用enable_if
將使函數'消失',這可能會讓用戶感到困惑。典型症狀是錯誤消息,如error: no matching function for call to expression
。這並沒有向用戶確切地傳達違反了要求。
您應該改爲使用static_assert
來強制您的要求,假設C++ 0x。如果您使用的是C++ 03,那麼您是否應該使用static_assert
(例如Boost的STATIC_ASSERT
)的仿真是一種折騰,因爲這通常意味着交換另一個錯誤消息。
對比度:
// SFINAE for types that do not decay to int
template<
typename T
, typename = typename std::enable_if<
std::is_same<
typename std::decay<T>::type
, int
>::value
>::type
>
void
f(T&&)
{}
// using static assert instead
template<
typename T
>
void
g(T&&)
{
static_assert(std::is_same<typename std::decay<T>::type, int>::value
, "Constraints violation");
}
使用GCC做f("violation")
我得到以下錯誤(這兩個消息都與文件名和行號):
error: no matching function for call to 'f(const char [10])'
在另一方面,g("violation")
產量:
error: static assertion failed: "Constraints violation"
現在想象你使用清晰明確的消息n你的斷言,如模板foo
內部的foo: parameter type must be CopyConstructible
。因此,SFINAE和static_assert
有點對立,因此既有明確的約束違規消息,又有巧妙的過載並不總是可能的和/或容易的。
你想要做的事情很容易實現使用Boost.ConceptCheck。但是它需要寫出非線性代碼:約束類。我也不認爲它在可用的地方使用static_assert
,所以錯誤消息可能不會那麼好。這可能會在未來發生變化。
另一種可能性是使用static_assert
+類型特徵。這種方法的有趣之處在於,使用C++ 0x時,庫帶有一系列有用的特性,您可以直接使用,而無需編寫外部代碼。更有意思的是,特徵的使用並不侷限於書寫限制,它們也可以與SFINAE一起使用來製造聰明的過載。
但是,沒有可用的特徵來檢查類型是否支持特定的操作成員,可能是由於C++處理函數名稱的方式。我們不能使用像has_member<T, &T::member_to_test_for>
之類的東西,因爲只有當我們測試的成員首先存在時纔會有意義(忽略重載等事情以及我們還需要將成員的簽名傳遞給特徵的事實) 。
下面是如何轉換任意表達式爲特徵:
template<typename T>
struct void_ {
typedef void type;
};
template<typename T>
struct trait {
private:
typedef char yes[1];
typedef char no[2];
template<typename U>
static
yes&
test(U&&
, typename void_<decltype(std::declval<U&>().member())>::type* = 0);
static
no&
test(...);
public:
static constexpr bool value = sizeof test(std::declval<T>()) == sizeof(yes);
};
注意如何相當大的,這是。編寫一個Boost.ConceptCheck約束類可能更容易(但記住,不可重複使用SFINAE)。
任意表達式是std::declval<U&>().member()
。在這裏,要求是給定的左值參考U
(或T
對於特徵爲真的情況(如果您願意的話)),那麼調用member()
就是有效的。
您還可以檢查出表達式的類型(即任何的member
超載已經提取了該表達式的結果類型)可轉換爲A型(不檢查是否是那種類型,這太限制沒有很好的理由)。然而,這會使這個特性膨脹,再次使這個變得更受限制。
我不知道如何使static_assert
函數模板的簽名的一部分(這似乎是你想要的東西),但它可以出現在類模板中。 Boost.ConceptCheck也不支持這一點。
你可以設置某種typetrait來測試類是否有給定的成員函數,但是如果你嘗試傳遞一個無效的模板參數,那麼你得到的所有東西都是編譯時錯誤,案子。那麼爲什麼要麻煩。 –
我不明白使用接口類的問題是什麼...... –
出於興趣,爲什麼這需要是模板方法? –