[英]is there a way to convert a template's substitution failure into a bool value (true/false) or tags (std::true_type/std::false_type)
我正在以C ++ 17風格在SFINAE上“玩”一點,並且我試圖實現一種結果,在該結果中,替換失敗而不是僅導致編譯器移至下一種情況,而是導致了“編譯器”(進行了這種嘗試的類)(通過false
/ std::false_type
)報告替換失敗,然后編譯器移至下一種情況。
我目前的嘗試歸結為這樣的事情:
template <typename T>
class logic_value
{
static constexpr bool result = std::is_same<
std::enable_if_t<T, std::true_type>,
std::true_type>;
};
template <typename T>
inline constexpr bool lv = logic_value<T>::result;
(用法示例:)
template <typename T>
std::enable_if_t<
lv<decltype(std::declval<T>() + std::declval<T>())> /* has plus operator */
&&
(lv<decltype(std::declval<T>().func_foo())> || lv<decltype(std::declval<T>().func_bar())>) /*has either func_foo() or func_bar() */
&&
lv<T&> /* can have a reference */
&&
(!lv<decltype(std::declval<T>().func_foobar())>) /* does NOT have a func_foobar() */
, T> const & Ioo(T const &);
但是它不像我想象的那樣起作用...://當我使用logic not
( !
)運算符來確保測試類型中的某些內容不存在時,尤其棘手。
這樣做的方法是使用檢測慣用語,您希望使用適當的別名進行is_detected
。
在您的特定情況下:
template <typename T> using has_plus_t = decltype(std::declval<T>() + std::declval<T>());
template <typename T> using func_foo_t = decltype(std::declval<T>().func_foo());
template <typename T> using func_bar_t = decltype(std::declval<T>().func_bar());
template <typename T> using func_foobar_t = decltype(std::declval<T>().func_foobar());
template <typename T>
enable_if_t<
is_detected_v<has_plus_t, T>
&&
(is_detected_v<func_foo_t, T> || is_detected_v<func_bar_t, T>)
&&
is_detected_v<add_lvalue_reference_t, T>
&&
!is_detected_v<func_foobar_t, T>
, T> const & Ioo(T const &);
您無法在這種情況下擁有要測試的表達式,因為一旦失敗,整個事情就會失敗。您的邏輯允許並要求某些表達式失敗-因此,您需要控制所有這些表達式的實例化。 這就是檢測慣用語的目的。
logical_value
的問題是,在發生替換錯誤的情況下,您不向編譯器提供替代路徑。
我做這些事情是這樣的:
#include <utility>
#include <array>
template<typename T, typename U>
constexpr auto check_addition(int) -> decltype(std::declval<T>() + std::declval<U>() , std::true_type{});
template<typename T, typename U>
constexpr std::false_type check_addition(...);
template<typename T, typename U>
constexpr bool can_add = decltype(check_addition<T, U>(0))::value;
int main() {
static_assert(can_add<int, float>);
static_assert(!can_add<std::string, float>);
}
這個想法是利用兩個重載,一個重載特定類型的參數(在我的例子中為int
),另一個重載省略號。 當我們以int
作為參數調用該重載函數時,編譯器將首先在必須執行所需檢查的地方檢查int
重載。
逗號運算符用於提供true_type
作為返回類型,以確保檢查成功完成。
如果第一個重載SFINAE失敗,則選擇第二個重載,該重載始終返回false_type
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.