[英]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;
}
The program above will output: 上面的程序将输出:
1
0
It shows the template has_push_back
doesn't work if the function push_back
is inherited. 它显示了如果继承了push_back
函数,则模板has_push_back
不起作用。
Is there a way to make it work even if it is inheried? 即使经过修复,有没有办法使它起作用?
Here's a solution using void_t
, which is standard in C++17 and also comes with additional utilities such as is_detected_exact
in the Library Fundamentals v2 TS, taking most of the work out of 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> {};
Or with future utilities : 或与未来的实用程序 :
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>;
If you'd like to learn about void_t
in detail, I suggest checking out Walter Brown's CppCon 2015 talks . 如果您想详细了解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;
};
According to this answer, your code could look like this: 根据此答案,您的代码可能如下所示:
#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;
};
All credits to @jork 所有学分归@jork
You've probably used code from this answer but it isn't working with inherited functions. 您可能已经使用了此答案中的代码,但它不适用于继承的函数。
For the sake of completeness, I'd like to post another approach not previously mentioned. 为了完整起见,我想发布另一种以前没有提到的方法。
This is based on functions' definitions and an alias declaration. 这基于函数的定义和别名声明。
It follows a minimal, working example: 它遵循一个最小的有效示例:
#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.