检查一个类
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!