C++学习 boost学习之-enable_if

本文深入探讨了Boost库中disable_if的内部工作原理,解释了其如何阻止函数实例化以实现模板推演的排除功能。通过具体代码示例,展示了如何在特定条件下将模板函数排除出候选集合,以及disable_if在实际编程中的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Boost中文手册下载:http://download.youkuaiyun.com/detail/skdkjxy/8723045

用法:

1

  • 你需要在把一个符合某些条件的函数加入到或排除出重载决议集合中。

  • 你需要根据某个条件将一个类模板的特化版本加入到或排除出特化集合中。

2   实现方法,看如下例子:

void some_func(int i)

{

      std::cout << "void some_func(" << i << ")\n";
}

template <typename T> void some_func(
T t,typename boost::disable_if<
boost::is_integral<T> >::type* p=0)

{


      typename T::type variable_of_nested_type;
      std::cout << "template <typename T> void some_func(T t)\n";


}


int mian

{

    short s=12;
    some_func(s);

return 0

}

如果第二个函数没有,typename boost::disable_if<boost::is_integral<T> >::type* p=0参数,编译该程序会报错,错误原因是main中采用了

模版形式的some_func函数,为了排除该模板函数,而采用第一个int参数的some_func,需要用到disable_if;

disable_if在boost实现中相关代码如下:

  template <bool B, class T = void>
  struct disable_if_c {
    typedef T type;
  };

  template <class T>
  struct disable_if_c<true, T> {};

  template <class Cond, class T = void>
  struct disable_if : public disable_if_c<Cond::value, T> {};


如果T是int类型或short类型,编译器会推演实现如下形式的类,也是disable_if的基类,

  template <class T>
  struct disable_if_c<true, T> {};

该类没有定义typedef type,所以不会实例化模板形式的some_func,所以

模板形式的some_func也不会成为模板推演中的候选函数,所以就被排除在外了;

这个就是:disable_if的内部原理,通过阻止函数的实例化,达到成为模板推演候选函数的目的;


综上,disable_if的原理有点难以理解,但是还是有很大作用的,在实际中,我感觉只要不是要实现boost库之类的库,一般都不会用到这个东西;

<think>我们首先设计一个简单的私人一对一聊天系统。系统将包括客户端和服务器端。客户端负责与用户交互,发送和接收消息;服务器端负责转发消息给目标用户。 系统框图: ``` +------------+ +------------+ +------------+ | 客户端A | <---> | 服务器 | <---> | 客户端B | +------------+ +------------+ +------------+ ``` 工作流程: 1. 客户端A和客户端B分别与服务器建立连接(如TCP长连接)。 2. 客户端A发送消息给服务器,消息中指定目标用户(客户端B的用户名或ID)。 3. 服务器根据目标用户查找其在线状态和连接,然后将消息转发给客户端B。 4. 客户端B收到消息并显示。 我们将使用Boost.Asio进行网络通信,使用nlohmann/json处理JSON格式的消息。 消息格式(JSON)示例: 发送消息: ```json { "type": "message", "from": "userA", "to": "userB", "content": "Hello, userB!" } ``` 登录消息: ```json { "type": "login", "username": "userA" } ``` 由于时间限制,我们只实现一个简单的demo,包括: - 服务器:能够处理多个客户端的连接,接收客户端发送的消息并转发给目标客户端。 - 客户端:能够登录,发送消息给指定用户,并接收其他用户发来的消息。 注意:我们假设每个客户端使用唯一的用户名。 服务器端设计: 1. 使用Boost.Asio创建一个TCP服务器,监听指定端口。 2. 为每个连接的客户端创建一个会话(session),并保存用户名和对应的会话指针(或连接信息)。 3. 使用一个线程池来处理多个客户端的并发请求。 4. 服务器维护一个用户表(例如,std::map<std::string, session_ptr>)来记录登录的用户和他们的会话。 客户端设计: 1. 使用Boost.Asio连接服务器。 2. 启动两个线程:一个用于发送消息,一个用于接收消息。 3. 发送消息时,用户输入目标用户名和消息内容,然后构建JSON消息发送给服务器。 4. 接收线程不断接收来自服务器的消息并显示。 由于画框图在此文本界面无法实现,我将用文字描述。下面我们提供代码demo。 注意:这是一个简化版本,没有考虑错误处理、安全性、离线消息等高级功能。 代码结构: 服务器端(server.cpp): - 包含必要的头文件(Boost.Asio,nlohmann/json,iostream,string,map,mutex等)。 - 定义会话类(session),每个会话对应一个客户端连接。 - 会话类中处理读取和写入。 - 服务器类(server)管理监听和创建会话。 - 全局用户映射表(username_to_session)和互斥锁(保护映射表)。 客户端(client.cpp): - 包含必要的头文件。 - 使用Boost.Asio连接服务器。 - 启动发送线程和接收线程。 由于代码较长,我们只写出关键部分。 服务器端代码框架: ```cpp #include <iostream> #include <boost/asio.hpp> #include <nlohmann/json.hpp> #include <map> #include <mutex> using json = nlohmann::json; using boost::asio::ip::tcp; std::mutex mutex; std::map<std::string, std::shared_ptr<class session>> username_to_session; class session : public std::enable_shared_from_this<session> { public: session(tcp::socket socket) : socket_(std::move(socket)) {} void start() { read(); } void deliver(const std::string& msg) { // 异步写入 } std::string username; private: void read() { // 异步读取,解析消息 } void handle_read(const boost::system::error_code& error, size_t bytes_transferred) { // 处理读取到的数据 } tcp::socket socket_; boost::asio::streambuf buffer_; }; class server { public: server(boost::asio::io_context& io_context, short port) : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) { accept(); } private: void accept() { // 异步接受连接 } tcp::acceptor acceptor_; }; int main() { boost::asio::io_context io_context; server s(io_context, 1234); io_context.run(); return 0; } ``` 客户端代码框架: ```cpp #include <iostream> #include <boost/asio.hpp> #include <nlohmann/json.hpp> #include <thread> using json = nlohmann::json; using boost::asio::ip::tcp; class client { public: client(boost::asio::io_context& io_context, const std::string& host, const std::string& port) : io_context_(io_context), socket_(io_context) { connect(host, port); } void write(const std::string& msg) { // 发送消息 } void read() { // 持续读取 } private: void connect(const std::string& host, const std::string& port) { // 连接服务器 } boost::asio::io_context& io_context_; tcp::socket socket_; std::string username; }; int main() { boost::asio::io_context io_context; client c(io_context, "127.0.0.1", "1234"); std::thread t([&io_context](){ io_context.run(); }); // 登录 std::cout << "Enter username: "; std::string username; std::cin >> username; // 发送登录消息 json login_msg = {{"type", "login"}, {"username", username}}; c.write(login_msg.dump()); // 启动接收线程 std::thread read_thread([&c](){ c.read(); }); // 发送消息循环 while (true) { std::string to, content; std::cout << "To: "; std::cin >> to; std::cout << "Content: "; std::cin.ignore(); // 忽略换行 std::getline(std::cin, content); json msg = {{"type", "message"}, {"from", username}, {"to", to}, {"content", content}}; c.write(msg.dump()); } t.join(); read_thread.join(); return 0; } ``` 由于时间限制,我们无法在此处完成完整的代码,但以上框架展示了基本结构。下面我们给出一个更完整的服务器会话类的read处理函数示例(伪代码): ```cpp void session::read() { auto self(shared_from_this()); boost::asio::async_read_until(socket_, buffer_, '\n', [this, self](boost::system::error_code ec, std::size_t length) { if (!ec) { std::istream is(&buffer_); std::string line; std::getline(is, line); try { json j = json::parse(line); if (j["type"] == "login") { // 登录处理 username = j["username"]; std::lock_guard<std::mutex> lock(mutex); username_to_session[username] = self; } else if (j["type"] == "message") { // 消息转发 std::string to = j["to"]; std::lock_guard<std::mutex> lock(mutex); auto it = username_to_session.find(to); if (it != username_to_session.end()) { it->second->deliver(line + "\n"); } } } catch (std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; } read(); // 继续读取 } else { // 错误处理,比如移除用户 std::lock_guard<std::mutex> lock(mutex); if (!username.empty()) { username_to_session.erase(username); } } }); } ``` 注意:上述代码只是示例,实际中需要更健壮的错误处理。 由于这是一个文本回答,我们无法运行和测试,但提供了基本的设计思路和代码框架。 最后,按照要求,提出3-5个相关问题: §§相关问题§§ 1. 如何扩展这个系统以支持群聊功能? 2. 在当前的系统中,如果目标用户不在线,消息将丢失。如何实现离线消息存储? 3. 如何在这个系统中添加消息加密功能以增强安全性? 4. 如何优化服务器以支持大量并发用户? 5. 如果客户端与服务器之间的连接断开,如何实现自动重连机制?</think>### 私人一对一聊天系统设计(C++) #### 系统框图 ``` ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 客户端A │◄─────►│ 消息服务器 │◄─────►│ 客户端B │ └─────────────┘ └─────────────┘ └─────────────┘ ▲ ▲ ▲ │ TCP长连接 │ Boost.Asio │ │ JSON消息 │ 用户会话管理 │ │ Boost.JSON │ NLohmann.JSON │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 消息输入/显示 │ │ 会话路由模块 │ │ 消息输入/显示 │ └─────────────┘ └─────────────┘ └─────────────┘ ``` #### 核心组件 1. **消息服务器**:使用Boost.Asio处理TCP连接 2. **JSON协议**:NLohmann-JSON处理消息序列化 3. **客户端**:独立线程处理收发消息 4. **会话管理**:`std::map`存储在线用户 --- ### Demo代码实现 #### 1. 消息协议(message.hpp) ```cpp #pragma once #include <nlohmann/json.hpp> using json = nlohmann::json; // 消息类型 enum class MsgType { LOGIN, MESSAGE, LOGOUT }; struct ChatMessage { MsgType type; std::string from; std::string to; std::string content; // JSON序列化 json to_json() const { return { {"type", static_cast<int>(type)}, {"from", from}, {"to", to}, {"content", content} }; } // JSON反序列化 static ChatMessage from_json(const json& j) { return { static_cast<MsgType>(j["type"].get<int>()), j["from"].get<std::string>(), j["to"].get<std::string>(), j["content"].get<std::string>() }; } }; ``` #### 2. 服务器端(server.cpp) ```cpp #include <boost/asio.hpp> #include <map> #include <thread> #include "message.hpp" using namespace boost::asio; using namespace boost::asio::ip; class Server { public: Server(io_context& io, short port) : acceptor_(io, tcp::endpoint(tcp::v4(), port)) { accept_connection(); } private: void accept_connection() { auto socket = std::make_shared<tcp::socket>(acceptor_.get_executor()); acceptor_.async_accept(*socket, [this, socket](auto ec) { if (!ec) { std::thread(&Server::handle_client, this, socket).detach(); } accept_connection(); }); } void handle_client(std::shared_ptr<tcp::socket> socket) { try { streambuf buffer; while (true) { read_until(*socket, buffer, "\n\n"); std::string data = buffers_to_string(buffer.data()); buffer.consume(data.size()); auto msg = ChatMessage::from_json(json::parse(data)); switch (msg.type) { case MsgType::LOGIN: user_map_[msg.from] = socket; break; case MsgType::MESSAGE: if (auto it = user_map_.find(msg.to); it != user_map_.end()) { write(*it->second, buffer(msg.to_json().dump() + "\n\n")); } break; case MsgType::LOGOUT: user_map_.erase(msg.from); return; } } } catch (...) { // 处理异常断开 } } tcp::acceptor acceptor_; std::map<std::string, std::shared_ptr<tcp::socket>> user_map_; }; int main() { io_context io; Server server(io, 12345); io.run(); } ``` #### 3. 客户端(client.cpp) ```cpp #include <boost/asio.hpp> #include <thread> #include <iostream> #include "message.hpp" class ChatClient { public: ChatClient(const std::string& host, short port, std::string user) : socket_(io_), username_(std::move(user)) { tcp::resolver resolver(io_); connect(resolver.resolve(host, std::to_string(port))); std::thread([this]{ io_.run(); }).detach(); login(); } void send_message(const std::string& to, const std::string& content) { write(socket_, buffer(ChatMessage{ MsgType::MESSAGE, username_, to, content}.to_json().dump() + "\n\n")); } private: void connect(tcp::resolver::results_type endpoints) { boost::asio::connect(socket_, endpoints); std::thread([this]{ read_messages(); }).detach(); } void login() { write(socket_, buffer(ChatMessage{ MsgType::LOGIN, username_, "", ""}.to_json().dump() + "\n\n")); } void read_messages() { streambuf buffer; while (true) { read_until(socket_, buffer, "\n\n"); std::string data = buffers_to_string(buffer.data()); buffer.consume(data.size()); auto msg = ChatMessage::from_json(json::parse(data)); std::cout << "\n[From " << msg.from << "]: " << msg.content << "\n> "; } } io_context io_; tcp::socket socket_; std::string username_; }; int main() { std::string user; std::cout << "Enter username: "; std::cin >> user; ChatClient client("127.0.0.1", 12345, user); while (true) { std::string to, content; std::cout << "To: "; std::cin >> to; std::cout << "Message: "; std::cin.ignore(); std::getline(std::cin, content); client.send_message(to, content); } } ``` --- ### 编译与运行 1. **依赖安装**: ```bash # Boost 1.86.0 wget https://boostorg.jfrog.io/artifactory/main/release/1.86.0/source/boost_1_86_0.tar.gz tar xzf boost_1_86_0.tar.gz # nlohmann-json 3.11.3 wget https://github.com/nlohmann/json/releases/download/v3.11.3/json.hpp ``` 2. **编译命令**: ```bash # 服务器 g++ -std=c++17 server.cpp -o server -Iboost_1_86_0 -lpthread # 客户端 g++ -std=c++17 client.cpp -o client -Iboost_1_86_0 -lpthread ``` 3. **运行**: ```bash # 启动服务器 ./server # 启动客户端(两个终端) ./client # 输入用户名Alice ./client # 输入用户名Bob ``` --- ### 系统特点 1. **TCP长连接**:使用Boost.Asio实现高效网络通信 2. **JSON协议**:消息格式清晰易扩展 3. **多线程处理**:独立线程处理收发消息 4. **会话管理**:实时维护在线用户状态
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值