提问人:Parker Coates 提问时间:5/10/2023 更新时间:5/10/2023 访问量:106
如何检查一个类是否有一个或多个具有给定名称的方法?
How to check if a class has one or more methods with a given name?
问:
有许多不同的技巧可以检查一个类是否具有名为 的方法。例如:Foo
bar
- 如果我们关心方法签名,我们就会围绕类似的东西构建一个特征
std::void_t<decltype(static_cast<ing(Foo::*)(char) const>(&Foo::bar))>
- 如果我们不关心签名,我们可以使用类似的东西
std::void_t<decltype(&Foo::bar)>
如果有多个名为 的方法,则前者继续正常工作(因为最多有一个重载将与 兼容),但是,后者会中断,可能是因为变得模棱两可。Foo
bar
static_cast
decltype(&Foo::bar)
有没有一种技术可以检测一个类是否具有一个或多个具有给定名称的方法,而不管方法签名如何?如果可以在 C++ 中工作,则加分14。
示例代码(Godbolt 链接):
#include <type_traits>
template<typename T, typename = void> struct HasIntBar_t : std::false_type {};
template<typename T> struct HasIntBar_t<T, std::void_t<decltype(static_cast<int(T::*)(char)>(&T::bar))>> : std::true_type {};
template<typename T> inline constexpr bool HasIntBar = HasIntBar_t<T>::value;
template<typename T, typename = void> struct HasAnyBar_t : std::false_type {};
template<typename T> struct HasAnyBar_t<T, std::void_t<decltype(&T::bar)>> : std::true_type {};
template<typename T> inline constexpr bool HasAnyBar = HasAnyBar_t<T>::value;
////////////////////////////////////
// Test Types:
struct None {};
struct OneInt
{
int bar(char);
};
struct OneIntInherited : public OneInt {};
struct OneDouble
{
double bar() const;
};
struct OneDoubleInherited : public OneDouble {};
struct TwoDirect
{
int bar(char);
double bar() const;
};
struct TwoInherited : public OneInt, public OneDouble
{
using OneInt::bar; // Required to avoid ambiguity
using OneDouble::bar; // Required to avoid ambiguity
};
struct OneInheritedOneDirect : public OneInt
{
using OneInt::bar; // Required to avoid hiding
double bar() const;
};
struct OneInheritedOneDirect2 : public OneDouble
{
using OneDouble::bar; // Required to avoid hiding
int bar(char);
};
////////////////////////////////////
// Tests:
static_assert(HasIntBar<None> == false);
static_assert(HasIntBar<OneInt> == true);
static_assert(HasIntBar<OneIntInherited> == true);
static_assert(HasIntBar<OneDouble> == false);
static_assert(HasIntBar<OneDoubleInherited> == false);
static_assert(HasIntBar<TwoDirect> == true);
static_assert(HasIntBar<TwoInherited> == true);
static_assert(HasIntBar<OneInheritedOneDirect> == true);
static_assert(HasIntBar<OneInheritedOneDirect2> == true);
static_assert(HasAnyBar<None> == false);
static_assert(HasAnyBar<OneInt> == true);
static_assert(HasAnyBar<OneIntInherited> == true);
static_assert(HasAnyBar<OneDouble> == true);
static_assert(HasAnyBar<OneDoubleInherited> == true);
static_assert(HasAnyBar<TwoDirect> == true); // FAILS!
static_assert(HasAnyBar<TwoInherited> == true); // FAILS!
static_assert(HasAnyBar<OneInheritedOneDirect> == true); // FAILS!
static_assert(HasAnyBar<OneInheritedOneDirect2> == true); // FAILS!
答:
5赞
Artyer
5/10/2023
#1
如果在多个碱基中找到名称查找,则可以利用名称查找的模糊性。首先创建一个从你的类型派生的结构体和一些具有单个成员的虚拟类型,然后检查该派生类型是否可以找到 。如果可以的话,它不是模棱两可的,因为它是在 derived 中发现的,而不是在 中,所以没有条形图。否则有一个:T
bar
bar
T
T
T
bar
struct dummy_bar { int bar; };
template<typename T, bool IsClass = std::is_class<T>::value>
struct HasAnyBar_t {
static_assert(!std::is_final<T>::value, "Cannot check HasAnyBar<T> on final classes for implementation reasons");
template<typename U>
static auto check(int) -> decltype(U::bar, void(), std::false_type{});
template<typename U>
static std::true_type check(long); // Above was ambiguous, so bar did exist in T
struct derived : T, dummy_bar {};
static constexpr bool value = decltype(check<derived>(0))::value;
};
template<typename T>
struct HasAnyBar_t<T, false> : std::false_type {};
template<typename T>
constexpr bool HasAnyBar = HasAnyBar_t<T>::value;
这将检查名称为 :function overload sets with templates、static data members、non-static data members 和 members types。bar
评论
0赞
Parker Coates
5/10/2023
非常感谢!这是令人愉快的讨厌,非常适合我的需求。我把这个想法转换成使用,因为我个人觉得它更干净(并在我的 C++14 代码库中本地实现):godbolt.org/z/xsqn11KMKvoid_t
void_t
评论
bar
bar
bar