我有一個簡單的 SFINAE 檢查器,用于檢查給定型別 ( T) 是否已為其operator==定義。
這通常作業得很好,但它不適用于std::pair<>.
我想我明白為什么它不起作用 -std::pair<>似乎無條件地提供operator==支持,即使它的一對底層型別沒有。
我正在征求關于如何更正我的 SFINAEoperator==檢查器的意見,以便它與pair<>
您可以在https://onlinegdb.com/rmAQS7V091在線測驗此代碼
但為了完整起見,它也直接包含在此處:
#include <iostream>
#include <functional> // needed for std::equal_to
#include <iterator>
using namespace std;
namespace
{
using namespace std;
/**
* LIFTED -@todo add docs/reference
* from Stroustrup C 11 book - page 800
*/
struct substitution_failure
{
};
/**
* LIFTED -@todo add docs/reference
* from Stroustrup C 11 book - page 800
*/
template < typename T > struct substitution_succeeded:true_type
{
};
template <> struct substitution_succeeded <substitution_failure >:false_type
{
};
#define STROIKA_FOUNDATION_CONFIGURATION_DEFINE_HAS(NAME, XTEST) \
namespace Private_ { \
template <typename T> \
struct NAME##_result_impl { \
template <typename X> \
static auto check (const X& x) -> decltype (XTEST); \
static substitution_failure check (...); \
using type = decltype (check (declval<T> ())); \
}; \
} \
template <typename T> \
using NAME##_result = typename Private_::NAME##_result_impl<T>::type; \
template <typename T> \
struct has_##NAME : integral_constant<bool, not is_same<NAME##_result<T>, substitution_failure>::value> { \
}; \
template <typename ITERABLE> \
constexpr bool Has##NAME##_v = has_##NAME<ITERABLE>::value;
STROIKA_FOUNDATION_CONFIGURATION_DEFINE_HAS (eq, (x == x)); // SEE https://stroika.atlassian.net/browse/STK-749
STROIKA_FOUNDATION_CONFIGURATION_DEFINE_HAS (equal_to, (static_cast<bool> (std::equal_to<X>{}(x, x))));
class SimpleClassWithoutComparisonOperators
{
public:
SimpleClassWithoutComparisonOperators (size_t v);
SimpleClassWithoutComparisonOperators (const
SimpleClassWithoutComparisonOperators
& f);
~SimpleClassWithoutComparisonOperators ();
size_t GetValue () const;
static size_t GetTotalLiveCount ();
//explicit operator size_t () const { return fValue; }
SimpleClassWithoutComparisonOperators operator (const
SimpleClassWithoutComparisonOperators
& rhs) const
{
return SimpleClassWithoutComparisonOperators (fValue rhs.fValue);
}
private:
size_t fValue;
int fConstructed;
static size_t sTotalLiveObjects;
};
static_assert (!has_eq < SimpleClassWithoutComparisonOperators >::value);
using PAIR_ =
std::pair < SimpleClassWithoutComparisonOperators,
SimpleClassWithoutComparisonOperators >;
static_assert (!has_eq < PAIR_ >::value); /// THIS IS WHAT FAILS
}
int
main ()
{
cout << "Hello World";
return 0;
}
uj5u.com熱心網友回復:
要修復std::pair大小寫,您可能會專門為它設定特征:
template <typename T1, typename T2>
struct has_eq<std::pair<T1, T2>> :
integral_constant<bool, has_eq<T1>::value && has_eq<T1>::value>
{};
演示
uj5u.com熱心網友回復:
正如kenash0625正確指出的那樣,您需要專門化std::pair才能手動實施std::pair本身不執行的檢查。但是,此時,我建議使用 C 17 并且不使用宏來簡化您的實作:
template<
template<typename...> typename Detector,
typename T,
typename SFINAE = void>
constexpr inline bool is_detected_v = false;
template<
template<typename...> typename Detector,
typename T>
constexpr inline bool is_detected_v<
Detector, T, std::void_t<Detector<T>>> = true;
我們現在可以這樣實作has_eq:
template<typename T>
using has_eq_t = decltype(std::declval<T>() == std::declval<T>());
static_assert(is_detected_v<has_eq_t, std::pair<int, int>>);
我們也可以寫一個助手,它的首要目的是增加代碼的表現力:
template<typename T>
constexpr inline bool has_eq_v = is_detected_v<has_eq_t, T>;
static_assert( ! has_eq_v<SimpleClassWithoutComparisonOperators>);
雖然最初的問題還沒有解決,這個助手的第二個目的是我們可以對std::pair. 讓我們添加專業化:
template<typename T, typename U>
constexpr inline bool has_eq_v<std::pair<T, U>> = has_eq_v<T> && has_eq_v<U>;
在這里,我們可以為此類特定情況添加越來越多的專業化:
template<typename... Ts>
constexpr inline bool has_eq_v<std::tuple<Ts...>> = (has_eq_v<Ts> && ...);
現在檢查代碼:
static_assert ( ! has_eq_v<PAIR_>);
進一步閱讀:
- 你應該閱讀檢測習語,這是我的一個更靈活的實作
is_detected_v - C 20 概念使我們的實作方式更簡單。我認為這些概念是我們沒有
std::is_detected標準庫的主要原因。概念不需要它。
uj5u.com熱心網友回復:
這是我的天真修復:添加兩行代碼到#define,
template <typename X> \
static substitution_failure check (std::pair<X,X>); \
共:
#define STROIKA_FOUNDATION_CONFIGURATION_DEFINE_HAS(NAME, XTEST) \
namespace Private_ { \
template <typename T> \
struct NAME##_result_impl { \
template <typename X> \
static auto check (const X& x) -> decltype (XTEST); \
static substitution_failure check (...); \
template <typename X> \
static substitution_failure check (std::pair<X,X>); \
using type = decltype (check (declval<T> ())); \
}; \
} \
template <typename T> \
using NAME##_result = typename Private_::NAME##_result_impl<T>::type; \
template <typename T> \
struct has_##NAME : integral_constant<bool, not is_same<NAME##_result<T>, substitution_failure>::value> { \
}; \
template <typename ITERABLE> \
constexpr bool Has##NAME##_v = has_##NAME<ITERABLE>::value;
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/368732.html
