[英]How to check if a class has an inherited function at compile-time?
#include <vector>
#include <iostream>
#include <type_traits>
using namespace std;
template<typename Coll>
class has_push_back
{
using coll_type = decay_t<Coll>;
using True = char(&)[1];
using False = char(&)[2];
template<typename U, void(U::*)(const typename U::value_type&)>
struct SFINAE {};
template<typename T>
static True Test(SFINAE<T, &T::push_back>*);
template<typename T>
static False Test(...);
public:
enum { value = sizeof(Test<coll_type>(nullptr)) == sizeof(True) };
};
class MyColl : public vector<int> {};
int main()
{
cout << has_push_back<vector<int>>::value << endl;
cout << has_push_back<MyColl>::value << endl;
}
上面的程序將輸出:
1
0
它顯示了如果繼承了push_back
函數,則模板has_push_back
不起作用。
即使經過修復,有沒有辦法使它起作用?
這里有一個解決方案使用void_t
,這是在C ++ 17標准,還配備了額外的工具,如is_detected_exact
在圖書館基礎V2 TS,同時大部分的工作出的has_push_back
:
template<typename... Ts>
using void_t = void;
template<typename T>
using push_back_test = decltype(std::declval<T>().push_back(std::declval<typename T::const_reference>()));
template<typename T, typename = void>
struct has_push_back : std::false_type {};
template<typename T>
struct has_push_back<T, void_t<push_back_test<T>>> : std::is_same<push_back_test<T>, void> {};
或與未來的實用程序 :
template<typename T>
using push_back_test = decltype(std::declval<T>().push_back(std::declval<typename T::const_reference>()));
template<typename T>
using has_push_back = std::experimental::is_detected_exact<void, push_back_test, T>;
如果您想詳細了解void_t
,建議您查看Walter Brown的CppCon 2015演講 。
template<typename Coll>
struct has_push_back {
template<
typename T,
typename = decltype(
std::declval<T&>().push_back(std::declval<typename T::value_type>())
)
>
static std::true_type Test(int);
template<typename T>
static std::false_type Test(long);
using type = decltype(Test<Coll>(0));
static constexpr bool value = type::value;
};
根據此答案,您的代碼可能如下所示:
#include <type_traits>
// Primary template with a static assertion
// for a meaningful error message
// if it ever gets instantiated.
// We could leave it undefined if we didn't care.
template<typename, typename T>
struct has_push_back {
static_assert(
std::integral_constant<T, false>::value,
"Second template parameter needs to be of function type.");
};
// specialization that does the checking
template<typename C, typename Ret, typename... Args>
struct has_push_back<C, Ret(Args...)> {
private:
template<typename T>
static constexpr auto check(T*)
-> typename
std::is_same<
decltype( std::declval<T>().push_back( std::declval<Args>()... ) ),
Ret // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>::type; // attempt to call it and see if the return type is correct
template<typename>
static constexpr std::false_type check(...);
typedef decltype(check<C>(0)) type;
public:
static constexpr bool value = type::value;
};
所有學分歸@jork
您可能已經使用了此答案中的代碼,但它不適用於繼承的函數。
為了完整起見,我想發布另一種以前沒有提到的方法。
這基於函數的定義和別名聲明。
它遵循一個最小的有效示例:
#include <vector>
#include <type_traits>
#include<utility>
using namespace std;
template<typename T, typename... U>
constexpr auto f(int)
-> std::conditional_t<false, decltype(std::declval<T>().push_back(std::declval<U>()...)), std::true_type>;
template<typename, typename...>
constexpr std::false_type f(char);
template<typename T, typename... U>
using has_push_back = decltype(f<T, U...>(0));
class MyColl : public vector<int> {};
int main() {
static_assert(has_push_back<vector<int>, int>::value, "!");
static_assert(has_push_back<MyColl, int>::value, "!");
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.