输入特征以检查 class 是否具有成员函数
Type traits to check if class has member function
尝试创建一种方法来识别给定 class 是否具有可以调用的给定函数,以及 returns 某种类型。
知道我做错了什么吗?在给定 class 的情况下,是否有更好的方法来确定给定方法是否可调用?
#include <string>
#include <type_traits>
#define GENERATE_HAS_MEMBER_FUNC(func, rettype) \
template<typename T, class Enable = void> struct has_##func; \
template<typename T, class U> struct has_##func : std::false_type {}; \
template<typename T> \
struct has_##func<T, \
typename std::enable_if<std::is_same< \
typename std::result_of<decltype (&T::func)(T)>::type, \
rettype>::value>::type> : std::true_type{}; \
template<class T> constexpr bool has_##func##_v = has_##func<T>::value;
GENERATE_HAS_MEMBER_FUNC(str, std::string)
GENERATE_HAS_MEMBER_FUNC(str2, std::string)
GENERATE_HAS_MEMBER_FUNC(funca, std::string)
GENERATE_HAS_MEMBER_FUNC(strK, std::string)
GENERATE_HAS_MEMBER_FUNC(fancy, std::string)
GENERATE_HAS_MEMBER_FUNC(really, std::string)
struct A1 {
virtual std::string str() const { return ""; }
std::string strK() const { return ""; }
virtual std::string fancy()=0;
};
struct A2 : A1 {
std::string str() const override { return ""; }
std::string funca();
std::string fancy() override { return ""; }
std::string really(int a=0) const { return std::to_string(a); }
};
int main() {
static_assert(has_str_v<A1>,
"A1::str is virtual method with impl on base"); // MSVC: NO, clang: OK, GCC: NO
static_assert(has_strK_v<A1>,
"A1::strK is implemented inline "); // MSVC: NO, clang: OK, GCC: NO
static_assert(has_fancy_v<A1>,
"A1::fancy is a pure virtual method on base"); // MSVC: NO, clang: OK, GCC: NO
static_assert(!has_really_v<A1>,
"A1::really doesn't exist in A1"); // MSVC: OK, clang: OK, GCC: OK
static_assert(has_str_v<A2>,
"A2::str is override method "); // MSVC: OK, clang: OK, GCC: OK
static_assert(!has_str2_v<A2>,
"A2::str2 does not exist in A2"); // MSVC: NO, clang: OK, GCC: OK
static_assert(has_funca_v<A2>,
"A2::funca is defined (no impl) in A2"); // MSVC: OK, clang: OK, GCC: OK
static_assert(has_strK_v<A2>,
"A2::strK is implemented method on base"); // MSVC: OK, clang: OK, GCC: OK
static_assert(has_fancy_v<A2>,
"A1::fancy is a override of pure virtual method of base"); // MSVC: OK, clang: OK, GCC: OK
static_assert(has_really_v<A2>,
"A2::really has default param (can be invoked without params)"); // MSVC: OK, clang: NO, GCC: NO
return 0;
}
关于此实现的一些惊喜。
编辑:
在尝试实施@Jarod42 和@Vittorio Romeo 的绝妙建议时:
#define GENERATE_HAS_MEMBER_FUNC(func, rettype) \
template<class T> using _has_##func_chk = \
decltype(std::declval<T &>().func()); \
template<class T> constexpr bool has_##func##_v = \
is_detected_exact_v<rettype, _has_##func_chk, T>;
现在有两个测试用例在 VS2015 上仍然失败(没有任何意义):
static_assert(!has_really_v, "A1::really doesn't exist in A1");
static_assert(!has_str2_v, "A2::str2 does not exist in A2");
我可能遗漏了一些愚蠢的东西...有什么线索吗?
Is there a better way to determine if a given method is invoke'able given a class?
是的,您可以使用 detection idiom,它可以在 C++11 中实现 (链接页面包含有效实现).
举个例子:Cat
有 float Cat::purr(int)
方法吗?
struct Cat { float purr(int){} };
template<class T>
using has_purr =
decltype(std::declval<T&>().purr(std::declval<int>()));
static_assert(std::experimental::is_detected_exact_v<float, has_purr, Cat>);
所需的检测惯用法 C++17 依赖项在 C++11 中实现起来很简单:
template< class... >
using void_t = void;
struct nonesuch {
nonesuch() = delete;
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
我看到这是一个老问题,但答案取决于实验特性。
在 codereview.com there is answer which does not use experimental feature. Just in case here is answer copied from the source:
template <typename Container, typename Element>
using pushback_t = decltype(std::declval<Container>().push_back(std::declval<Element>()));
template <typename Container, typename Element, typename = std::void_t<>>
struct has_pushback : std::false_type{};
template <typename Container, typename Element>
struct has_pushback<Container, Element, std::void_t<pushback_t<Container, Element>>>:
std::true_type{};
template <typename Container, typename Element>
inline constexpr bool has_pushback_v = has_pushback<Container, Element>::value;
尝试创建一种方法来识别给定 class 是否具有可以调用的给定函数,以及 returns 某种类型。
知道我做错了什么吗?在给定 class 的情况下,是否有更好的方法来确定给定方法是否可调用?
#include <string>
#include <type_traits>
#define GENERATE_HAS_MEMBER_FUNC(func, rettype) \
template<typename T, class Enable = void> struct has_##func; \
template<typename T, class U> struct has_##func : std::false_type {}; \
template<typename T> \
struct has_##func<T, \
typename std::enable_if<std::is_same< \
typename std::result_of<decltype (&T::func)(T)>::type, \
rettype>::value>::type> : std::true_type{}; \
template<class T> constexpr bool has_##func##_v = has_##func<T>::value;
GENERATE_HAS_MEMBER_FUNC(str, std::string)
GENERATE_HAS_MEMBER_FUNC(str2, std::string)
GENERATE_HAS_MEMBER_FUNC(funca, std::string)
GENERATE_HAS_MEMBER_FUNC(strK, std::string)
GENERATE_HAS_MEMBER_FUNC(fancy, std::string)
GENERATE_HAS_MEMBER_FUNC(really, std::string)
struct A1 {
virtual std::string str() const { return ""; }
std::string strK() const { return ""; }
virtual std::string fancy()=0;
};
struct A2 : A1 {
std::string str() const override { return ""; }
std::string funca();
std::string fancy() override { return ""; }
std::string really(int a=0) const { return std::to_string(a); }
};
int main() {
static_assert(has_str_v<A1>,
"A1::str is virtual method with impl on base"); // MSVC: NO, clang: OK, GCC: NO
static_assert(has_strK_v<A1>,
"A1::strK is implemented inline "); // MSVC: NO, clang: OK, GCC: NO
static_assert(has_fancy_v<A1>,
"A1::fancy is a pure virtual method on base"); // MSVC: NO, clang: OK, GCC: NO
static_assert(!has_really_v<A1>,
"A1::really doesn't exist in A1"); // MSVC: OK, clang: OK, GCC: OK
static_assert(has_str_v<A2>,
"A2::str is override method "); // MSVC: OK, clang: OK, GCC: OK
static_assert(!has_str2_v<A2>,
"A2::str2 does not exist in A2"); // MSVC: NO, clang: OK, GCC: OK
static_assert(has_funca_v<A2>,
"A2::funca is defined (no impl) in A2"); // MSVC: OK, clang: OK, GCC: OK
static_assert(has_strK_v<A2>,
"A2::strK is implemented method on base"); // MSVC: OK, clang: OK, GCC: OK
static_assert(has_fancy_v<A2>,
"A1::fancy is a override of pure virtual method of base"); // MSVC: OK, clang: OK, GCC: OK
static_assert(has_really_v<A2>,
"A2::really has default param (can be invoked without params)"); // MSVC: OK, clang: NO, GCC: NO
return 0;
}
关于此实现的一些惊喜。
编辑: 在尝试实施@Jarod42 和@Vittorio Romeo 的绝妙建议时:
#define GENERATE_HAS_MEMBER_FUNC(func, rettype) \
template<class T> using _has_##func_chk = \
decltype(std::declval<T &>().func()); \
template<class T> constexpr bool has_##func##_v = \
is_detected_exact_v<rettype, _has_##func_chk, T>;
现在有两个测试用例在 VS2015 上仍然失败(没有任何意义): static_assert(!has_really_v, "A1::really doesn't exist in A1"); static_assert(!has_str2_v, "A2::str2 does not exist in A2");
我可能遗漏了一些愚蠢的东西...有什么线索吗?
Is there a better way to determine if a given method is invoke'able given a class?
是的,您可以使用 detection idiom,它可以在 C++11 中实现 (链接页面包含有效实现).
举个例子:Cat
有 float Cat::purr(int)
方法吗?
struct Cat { float purr(int){} };
template<class T>
using has_purr =
decltype(std::declval<T&>().purr(std::declval<int>()));
static_assert(std::experimental::is_detected_exact_v<float, has_purr, Cat>);
所需的检测惯用法 C++17 依赖项在 C++11 中实现起来很简单:
template< class... >
using void_t = void;
struct nonesuch {
nonesuch() = delete;
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
我看到这是一个老问题,但答案取决于实验特性。 在 codereview.com there is answer which does not use experimental feature. Just in case here is answer copied from the source:
template <typename Container, typename Element>
using pushback_t = decltype(std::declval<Container>().push_back(std::declval<Element>()));
template <typename Container, typename Element, typename = std::void_t<>>
struct has_pushback : std::false_type{};
template <typename Container, typename Element>
struct has_pushback<Container, Element, std::void_t<pushback_t<Container, Element>>>:
std::true_type{};
template <typename Container, typename Element>
inline constexpr bool has_pushback_v = has_pushback<Container, Element>::value;