C++:如何判断类中是否存在特定的成员函数?

       在模板开发中有时需要判断一个类中是否含特定的方法,然后根据判断结果开分支,编写不同的逻辑。下面就介绍一下最常用的一种方式:

template <typename U>
struct class_str {
    
    template <typename T, string(T::*)() = &T::str>
    static constexpr bool check(T*) { return true; };   //  (1)
    static constexpr bool check(...) { return false; }; //  (2)

    static constexpr bool ret = check(static_cast<U*>(0));  //  (3)
};

上面的代码将判断U中是否含有string str();方法,如果含的,则ret = true,否则ret = false。

在(3)中给check()方法传入了类型为U*的空指针,运行过程如下:

  • 如果U中含有string str();方法,则(1)和(2)两个check()方法将都会在编译期生成,但check(T*)最匹配static_cast<U*>(0)的结果,所以这时会调用(1)这个check(T*),返回true;
  • 如果U中不含有string str();方法,则只有(2)这个check()方法会在编译期生成, 于是调用(2)后返回false。

为了更好的看到效果,我们把“C++:举例说明如何使用enable_if和模板的函数指针参数“客户的例子改进一下:

#include <string>
#include <iostream>

using namespace std;


class Box {
public:
	string str() {
		return "yes";
	}
};

class Bin {
public:
	string str1() {
		return "no";
	}
};

template <typename U>
struct class_str {

	template <typename T, string(T::*)() = &T::str>
	static constexpr bool check(T*) { return true; };

	static constexpr bool check(...) { return false; };

	static constexpr bool ret = check(static_cast<U*>(0));
};

// 不含有string str()方法的非std::string类
template<typename T, 
        typename std::enable_if<std::is_class<T>::value && !std::is_same<T, string>::value, T>::type* = nullptr, 
        typename std::enable_if<!class_str<T>::ret, T>::type* = nullptr>
std::string str(T& t) {
	cout << "1.---------------------" << endl;
	return "null";
};

// std::string类
template<typename T, 
        typename std::enable_if<std::is_class<T>::value && std::is_same<T, string>::value, T>::type* = nullptr>
std::string str(T& t) {
	cout << "2.---------------------" << endl;
	return t;
};

// 含有string str()方法的非std::string类
template<typename T, 
        typename std::enable_if<std::is_class<T>::value && !std::is_same<T, string>::value, T>::type* = nullptr, 
        typename std::enable_if<class_str<T>::ret, T>::type* = nullptr>
std::string str(T& t) {
	cout << "3.---------------------" << endl;
	return t.str();
};

// 数值型
template<typename T, 
        typename std::enable_if<!std::is_class<T>::value && std::is_arithmetic<T>::value, T>::type* = nullptr>
std::string str(T&  t) {
	cout << "4.---------------------" << endl;
	return std::to_string(t);
};

int main() {
  string s = "sddds";
  cout << str<string>(s) << endl;
  
  bool j = true;
  cout << str<bool>(j) << endl;
  
  int i = 1000;
  cout << str<int>(i) << endl;
  
  float f = 10.6f;
  cout << str<float>(f) << endl;
  
  Box b1;
  cout << str<Box>(b1) << endl;
  
  Bin b2;
  cout << str<Bin>(b2) << endl;
  
  return 1;
}

运行结果:

2.---------------------
sddds
4.---------------------
1
4.---------------------
1000
4.---------------------
10.600000
3.---------------------
yes
1.---------------------
null

        以上代码中struct class_str使用了constexpr,这是C++11中才提供的,如果C++编译器不支持constexpr,则可以使用如下代码替代:

template <typename U>
struct class_str {

    template <typename T, string(T::*)() = &T::str>
    static char check(T*);
    template <typename T>
    static int check(...);

    const static bool ret = sizeof(check<U>(static_cast<U*>(0))) == sizeof(char);
};

参考文档

C++11之美

Problem while checking if function exist in c++
Is there any way to detect whether a function exists and can be used at compile time?

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中,成员函数可以作为回调函数使用。这是因为成员函数与普通的函数不同,它们需要通过对象来调用。回调函数通常用来在特定的事件发生时执行某个操作。 当将成员函数作为回调函数使用时,需要使用类对象来调用它。首先,我们需要定义一个回调函数的接口,在接口中声明回调函数的参数和返回类型。然后,在类中定义一个成员函数,该成员函数与回调函数的接口相匹配。 接下来,在程序中创建该类的对象,并将对象成员函数作为回调函数传递给需要注册回调函数的地方,通常是在其他类或函数中。通过传递对象的地址或引用,其他类或函数就可以调用该对象成员函数作为回调函数。 当事件触发时,那些注册了回调函数的地方就会调用相应的成员函数。由于成员函数是通过类对象调用的,它可以访问该类对象的成员变量和成员函数,以及其他相关的类信息。 通过使用成员函数作为回调函数,可以实现更灵活的程序设计。它可以方便地将代码逻辑封装在类中,并在需要的时候进行调用。此外,成员函数作为回调函数还可以在多线程编程中起到重要的作用,可以将任务委托给不同的线程进行执行。 总的来说,C++中可以使用成员函数作为回调函数,通过类对象来调用。这种用法可以帮助我们实现更灵活和模块化的程序设计,提高代码的重用性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值