C++模板类成员函数使用SFINAE特性匹配智能指针

本文通过一个实际项目案例,讲解了如何利用C++的模板类和SFINAE特性,设计一个既能处理普通类也能处理智能指针的成员函数。在类`RandomByWeight`中,通过模板函数重载和`std::enable_if`,实现了`push_back`函数对普通类和智能指针的支持,使得在不改变用户使用方式的情况下,提高了代码的通用性和效率。

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

为了讲解C++模板类成员函数如何使用SFINAE特性匹配智能指针,笔者使用最近在实际项目中的应用来进行说明。

最近在项目开发中需要一个根据设定权重来对一组数据进行随机选择的功能,项目中之前应该也有类似的需求,但是都是各自写各自的,没有一个通用的可以共用的代码。

在实际开发中,对一组数据进行随机选择是非常常用的功能,可能是均权随机,也可能是根据设定的权重进行随机,为了达到能通用共用的目的,写成一个模板类,代码如下:

template<typename T>
class RandomByWeight
{
public:
	RandomByWeight() : m_sum(0)
	{
	}
	
	void push_back(const T& v)
	{
		m_sum += v.GetWeight();
		m_vctSum.push_back(m_sum);
		m_vctData.push_back(v);
	}
	
	const T& RandomPickData() const
	{
		int t = Rand(0, m_sum - 1);
		int l = 0, r = (int)m_vctSum.size() - 1;
		while (l != r)
		{
			int m = (l + r) / 2;
			if (t >= m_vctSum[m])
				l = m + 1;
			else
				r = m;
		}
		return m_vctData[l];
	}
	
	inline const T& operator[](size_t index) const
	{
		Assert(index < m_vctData.size());
		return m_vctData[index];
	}
	
	inline auto begin()
	{
		return m_vctData.begin();
	}
	
	inline auto end()
	{
		return m_vctData.end();
	}
	
	inline auto size() const
	{
		return m_vctData.size();
	}
	
private:
	int			m_sum;
	vector<int> m_vctSum;
	vector<T>	m_vctData;
};

其中的Rand函数参见C语言随机数中的实现

使用该类的数据结构T需要实现GetWeight函数。比如:

struct IDWeight
{
	uint16 ID;
	uint Weight;

	inline uint GetWeight() const { return Weight; }
};

RandomByWeight<IDWeight> vct;

类中push_back函数使用值传递方式保存到容器中,但是如果数据结构比较大时,开销比较大,所以需要支持智能指针(不能直接使用指针,因为RandomByWeight类不进行内存释放)。

C++11/14标准库不支持智能指针的判断,所以需要自己进行判断:

template <typename T>
struct is_smart_pointer_helper : public std::false_type {};

template <typename T>
struct is_smart_pointer_helper<std::shared_ptr<T> > : public std::true_type {};

template <typename T>
struct is_smart_pointer_helper<std::unique_ptr<T> > : public std::true_type {};

template <typename T>
struct is_smart_pointer_helper<std::weak_ptr<T> > : public std::true_type {};

template <typename T>
struct is_smart_pointer_helper<std::auto_ptr<T> > : public std::true_type {};

template <typename T>
struct is_smart_pointer : public is_smart_pointer_helper<typename std::remove_cv<T>::type> {};

接下来修改push_back函数,让其既支持普通类,也支持智能指针。有一个非常简单的方式,就是按照普通类的实现方式,新写一个函数push_back_sp,把v.GetWeight(),改为v->GetWeight()即可,在使用智能指针时调用push_back_sp。即:

template<typename T>
class RandomByWeight
{
public:
	……
	void push_back(const T& v)
	{
		m_sum += v.GetWeight();
		m_vctSum.push_back(m_sum);
		m_vctData.push_back(v);
	}
	void push_back_sp(const T& v)
	{
		m_sum += v->GetWeight();
		m_vctSum.push_back(m_sum);
		m_vctData.push_back(v);
	}
	……
};

这样做虽然达到了目的,但改变了使用者的使用方式。最好的方式还是进行函数重载。为了达到函数重载,需要使用到C++11的SFINAE特性,该特性适用于模板函数,不能用于普通函数,也就是说需要把push_back写成模板函数,然后使用SFINAE特性来让编译器匹配。

使用C++11模板SFINAE特性重写序列化与反序列化一文中有说到,std::enable_if可以使用在以下三个方面:

  • 作为函数参数
  • 作为模板参数
  • 作为返回类型

下面就是作为函数参数的实现:

template<typename T>
class RandomByWeight
{
public:
	……
	template<typename U = T>
	void push_back(const typename std::enable_if<!is_smart_pointer<U>::value, U>::type& v)
	{
		m_sum += v.GetWeight();
		m_vctSum.push_back(m_sum);
		m_vctData.push_back(v);
	}

	template<typename U = T>
	void push_back(const typename std::enable_if<is_smart_pointer<U>::value, U>::type& v)
	{
		m_sum += v->GetWeight();
		m_vctSum.push_back(m_sum);
		m_vctData.push_back(v);
	}
	……
};

需要注意的是push_back函数的模板参数需要重新定义一个不同的名称比如U,并且等于类的模板参数T,enable_if中也需要使用新的模板参数名称U,否则可能会编译报错。

下面就是作为模板参数的实现:

template<typename T>
class RandomByWeight
{
public:
	……
	template<typename U = T, typename std::enable_if<!is_smart_pointer<U>::value, U>::type * = nullptr>
	void push_back(const T& v)
	{
		m_sum += v.GetWeight();
		m_vctSum.push_back(m_sum);
		m_vctData.push_back(v);
	}

	template<typename U = T, typename std::enable_if<is_smart_pointer<U>::value, U>::type * = nullptr>
	void push_back(const T& v)
	{
		m_sum += v->GetWeight();
		m_vctSum.push_back(m_sum);
		m_vctData.push_back(v);
	}
	……
};

由于push_back函数的返回值是void,所以不能作为返回类型进行重载,否则会出现“对重载函数的调用不明确”的错误,除非调用时特别指定类型(不符合预期,改变了用户的使用方式)

两种方式都可以,看各自的喜好!

参考:
https://stackoverflow.com/questions/41853159/how-to-detect-if-a-type-is-shared-ptr-at-compile-time
https://blog.csdn.net/sinat_17700695/article/details/109226122

<think>好的,用户想知道如何在Trae中集成或使用Claude-3.5-Sonnet模型。首先,我需要确认Trae是什么。可能用户指的是某个框架或工具,比如可能拼写错误,比如Trame、TRAE或者某个特定库。但根据上下文,可能是指某个AI模型部署平台或者API工具。假设Trae是一个支持模型集成的平台,用户需要添加Claude-3.5-Sonnet。 接下来,我需要回忆Claude-3.5-Sonnet的信息。根据引用[^1],Claude 3.5 Haiku即将布,但用户提到的是Sonnet。可能用户混淆了型号,需要确认。不过根据引用[1],Haiku是新的模型,而Sonnet是之前的版本。可能用户想用最新的Haiku,但问题中提到的是Sonnet,所以可能需要说明两者的区别。 然后,考虑如何在Trae中添加模型。通常,集成模型需要API访问、SDK使用或本地部署。需要分步骤说明:首先获取API访问权限,安装必要的库,配置环境变量,编写调用代码,处理异常,测试等。同时需要检查Trae是否支持ClaudeAPI,或者是否需要通过HTTP请求直接调用。 可能的问题包括:如何获取API密钥,如何处理认证,如何构造请求体,如何处理响应。需要确保用户按照正确的步骤操作,比如注册Anthropic账户,获取API密钥,安装anthropic库等。 另外,需要引用提供的参考资料,特别是引用[^1]提到的Claude 3.5的性能布信息,可能需要提醒用户注意模型版本可用性,比如Haiku即将布,是否会影响当前集成Sonnet的步骤。 还需要考虑用户可能遇到的常见问题,比如环境配置错误、权限问题、网络问题等,建议进行测试调试。最后,生成相关问题,帮助用户进一步了解模型集成后的优化应用场景。</think>要在Trae中集成Claude-3.5-Sonnet模型,需要遵循以下步骤(假设Trae是基于Python的AI开框架): ### 一、环境准备 1. 安装最新版Anthropic SDK ```bash pip install anthropic>=0.21.0 ``` 2. 配置API密钥 ```python import anthropic client = anthropic.Anthropic( api_key="sk-your-api-key-here" ) ``` ### 二、模型调用实现 ```python def claude_inference(prompt: str, model="claude-3.5-sonnet-20240620", max_tokens=1000): message = client.messages.create( model=model, max_tokens=max_tokens, messages=[ {"role": "user", "content": prompt} ] ) return message.content[0].text ``` ### 三、Trae框架集成 1. 创建模型适配器类 ```python class ClaudeAdapter(TraeBaseModel): def __init__(self, config): super().__init__(config) self.client = anthropic.Anthropic(api_key=config[&#39;api_key&#39;]) def predict(self, input_data): response = self.client.messages.create( model=self.config[&#39;model_version&#39;], max_tokens=self.config[&#39;max_tokens&#39;], messages=[{"role": "user", "content": input_data}] ) return self._format_output(response) ``` ### 四、配置参数示例 ```json { "model_type": "claude", "api_key": "sk-xxx", "model_version": "claude-3.5-sonnet-20240620", "max_tokens": 4096, "temperature": 0.7 } ``` 根据Anthropic的最新公告,Claude 3.5 Haiku模型将在本月晚些时候布,其编码能力已超越GPT-4o。集成时需注意模型版本的更新维护。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值