类型trait:检查类是否具有特定的函数(可能是inherit)
Type trait: Check if class have specific function (maybe inherit)
我知道有很多可能的方法可以检测类是否具有特定的函数,但没有一种真正适用于我的具体情况。除了继承函数之外,我当前的实现可以检查正确的成员函数。
#include <type_traits>
template<typename T>
class HasFoo {
template <typename U, int (U::*)(float)>
struct Check;
template <typename U>
static std::true_type Test(Check<U, &U::foo> *);
template <typename U>
static std::false_type Test(...);
public:
static constexpr bool value = decltype(Test<T>(0))::value;
};
struct A {
int foo(float);
};
struct B : public A {
};
struct C {
unsigned int foo(double);
};
struct D {
static int foo(float);
};
static_assert(HasFoo<A>::value, "A should have foo.");
static_assert(HasFoo<B>::value, "B should inherit foo from A.");
static_assert(!HasFoo<C>::value, "C should not have foo.");
static_assert(!HasFoo<D>::value, "Ds static foo should be false.");
活生生的例子。
此实现不适用于B.的static_assert
一个不可接受的解决方法是检查:
template <typename U, int (U::A::*)(float)>
struct Check; |
|- add base class
但在那里我必须知道基类,这应该避免。
有人知道如何检查派生函数吗?
编辑:如果根本不存在Foo,那么类型特征也应该起作用。
struct E {};
static_assert(!HasFoo<E>::value, "E does not have foo.");
这里有一种方法(适用于您的4个测试用例,但没有进行深入测试),感谢@Jarod42的改进(见最后的初始答案):
template <typename T>
int call_foo (int (T::*)(float));
template <typename C>
std::true_type has_foo(decltype(call_foo(&C::foo)));
template <typename C>
std::false_type has_foo (...);
template<typename T>
using HasFoo = decltype(has_foo<T>(0));
您的代码的问题是您期望的是U::*
,而&B::foo
是A::*
(而不是B::*
)。在这里,我让编译器通过使用隐式类型推导来选择T
的值,这样我就不会遇到这样的问题。
代码的工作原理如下:
- 如果
T
没有foo
成员,则编译器将选择has_foo
的第二个重载 - 如果
T
确实有foo
成员,编译器将尝试第一个重载,但由于没有匹配的call_foo
函数,因此将失败,因此它将再次选择第二个并生成std::false_type
表意文字的工作代码:http://ideone.com/erh93I.
如果你想的话,你可以把所有东西都放在class
中:
template <typename T>
class HasFoo {
template <typename C>
static int call_foo (int (C::*)(float));
template <typename C>
static std::true_type has_foo (decltype(call_foo(&C::foo)));
template <typename C>
static std::false_type has_foo (...);
public:
static constexpr bool value = decltype(has_foo<T>(0)){};
};
这里有一种老式的C++03方法。通常,它可以用作实用程序,并为任何方法或变量成型。
#define HasMember(NAME)
template<class Class, typename Type = void>
struct HasMember_##NAME
{
typedef char (&yes)[2];
template<unsigned long> struct exists;
template<typename V> static yes Check (exists<sizeof(static_cast<Type>(&V::NAME))>*);
template<typename> static char Check (...);
static const bool value = (sizeof(Check<Class>(0)) == sizeof(yes));
};
template<class Class>
struct HasMember_##NAME<Class, void>
{
typedef char (&yes)[2];
template<unsigned long> struct exists;
template<typename V> static yes Check (exists<sizeof(&V::NAME)>*);
template<typename> static char Check (...);
static const bool value = (sizeof(Check<Class>(0)) == sizeof(yes));
}
实例化:
HasMember(Foo);
用法:
HasMember_Foo<B>::value // without type (but then no overload allowed)
HasMember_Foo<C, int (C::*)(float)>::value // needs type
请注意,这里我提供了两个HasMember_Foo
,一个有类型,一个没有类型。它们适用于任何类型(不仅仅是int (X::*)(float)
特有的)。如果没有提到类型,那么类必须只有1个这样的方法(没有重载)。因此,提到这种类型总是更安全的;正如您在问题中所做的那样,具体类型为int (X::*)(float)
。顺便说一句,这也可以使用另一个宏来包含
如果没有这样的额外宏,在class C
和class D
的情况下,您可能必须指定方法的类型。
下面是您的代码演示。
这里假设,无论选择哪个类成员(函数或变量),都必须是public
作用域。即如果CCD_ 20是CCD_。
这里有一个带有<experimental/type_traits>
或<boost/type_traits.hpp>
的解决方案
#include <experimental/type_traits>
#include <iostream>
struct A {
auto foo() { return 0; }
};
struct B {
auto bar() { return 0.0; }
};
struct C : public A {
auto bAr() { return 0.0; }
};
struct D : public C {
auto baR() { return 0.0; }
};
template <typename T>
using HasFoo_t = decltype(std::declval<T&>().foo());
int main() {
std::cout << std::experimental::is_detected_v<HasFoo_t, A> << std::endl;
std::cout << std::experimental::is_detected_v<HasFoo_t, B> << std::endl;
std::cout << std::experimental::is_detected_v<HasFoo_t, C> << std::endl;
std::cout << std::experimental::is_detected_v<HasFoo_t, D> << std::endl;
}
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 如何获取std::result_of函数的返回类型
- 类型trait:检查类是否具有特定的函数(可能是inherit)
- 我们在C++"inherit"构造函数吗?什么是"inheriting"的确切定义