You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为指向支持operator<类型的指针模板类条件实现insert_sorted函数

PtrVector模板类条件化实现insert_sorted成员函数(声明与实现分离)

问题描述

我有一个容器模板类PtrVector,内部聚合了类型为T的std::vector,其中T实际是指向类型S的指针。我希望创建成员函数insert_sorted(),仅当T指向的类型S支持operator<()时才会被实例化。

我对模板仅了解基础内容,类型特性领域完全陌生。查阅了诸多类似问题后仍搞不清正确语法,似乎需要用到std::enable_if,但不知具体如何操作。理想情况下希望将函数的声明与实现分离,使用环境为MSVC 2022(基于C++17标准)。

现有代码(可编译,除insert_sorted外正常工作)

#include <vector>
#include <algorithm>
#include <type_traits>
#include <utility>
#include <assert.h>

// 禁用警告 C4251 和 C4275
#pragma warning(disable:4251 4275)

namespace supports
{
    namespace details { struct return_t {}; }

    template<typename T>
    details::return_t operator<(T const&, T const&);

    template<typename T>
    struct less_than : std::integral_constant<bool,
        !std::is_same<decltype(std::declval<std::remove_pointer<T> const&>() < std::declval<std::remove_pointer<T> const&>()), details::return_t>::value>
    {};

    template<typename T>
    struct greater_than : std::integral_constant<bool,
        !std::is_same<decltype(std::declval<T const&>() > std::declval<T const&>()), details::return_t>::value>
    {};

    template<typename T>
    struct equal : std::integral_constant<bool,
        !std::is_same<decltype(std::declval<T const&>() == std::declval<T const&>()), details::return_t>::value>
    {};

    template<typename T>
    struct not_equal : std::integral_constant<bool,
        !std::is_same<decltype(std::declval<T const&>() != std::declval<T const&>()), details::return_t>::value>
    {};
}

// PtrVector
template<typename T>
class PtrVector
{
public:
    typedef typename std::vector<T>::value_type value_type;
    typedef typename std::vector<T>::size_type size_type;
    typedef typename std::vector<T>::reference reference;
    typedef typename std::vector<T>::const_reference const_reference;
    typedef typename std::vector<T>::pointer pointer;
    typedef typename std::vector<T>::const_pointer const_pointer;
    typedef typename std::vector<T>::iterator iterator;
    typedef typename std::vector<T>::const_iterator const_iterator;
    typedef typename std::vector<T>::reverse_iterator reverse_iterator;
    typedef typename std::vector<T>::const_reverse_iterator const_reverse_iterator;

    PtrVector(bool owner = true, size_type reserve = 0);

    iterator                  begin();
    const_iterator            begin() const;
    iterator                  end();
    const_iterator            end() const;

    // 最初尝试的声明(存在问题)
    bool insert_sorted(const value_type& val, typename std::enable_if_t<supports::less_than<T>::value, int> = 0);

protected:
    std::vector<T> m_container;
};

// 最初尝试的实现
template<typename T>
bool PtrVector<T>::insert_sorted(const value_type& val, typename std::enable_if_t<supports::less_than<T>::value, int>)
{
    auto it = std::lower_bound(begin(), end(), val, [](const value_type& a, const value_type& b)->bool { return *a < *b; });

    if (it == end() || *val < *(*it))
    {
        m_container.insert(it, val);
        return true;
    }
    return false;
}

已实现但无法分离的写法

以下写法可以正常工作,但函数实现必须放在类声明内部:

template <typename = std::enable_if_t<supports::less_than<T>::value, int>>
bool insert_sorted(const value_type& val)
{
    auto it = std::lower_bound(begin(), end(), val, [](const value_type& a, const value_type& b)->bool { return *a < *b; });

    if (it == end() || *val < *(*it))
    {
        m_container.insert(it, val);
        return true;
    }
    return false;
}

错误的分离写法(声明不匹配)

我尝试了如下分离写法,但编译器提示声明与实现不匹配:

类内声明

template<typename = std::enable_if_t<supports::less_than<T>::value, int>>
bool insert_sorted(const value_type& val);

类外实现

template<typename T, typename = std::enable_if_t<supports::less_than<T>::value, int>>
bool PtrVector<T>::insert_sorted(const value_type& val)
{
    auto it = std::lower_bound(begin(), end(), val, [](const value_type& a, const value_type& b)->bool { return *a < *b; });

    if (it == end() || *val < *(*it))
    {
        m_container.insert(it, val);
        return true;
    }
    return false;
}

正确的分离写法

问题出在成员模板的定义语法上:类内声明的是成员自身的模板参数,而非类的模板参数。定义时需要先声明类的模板参数,再声明成员的模板参数,具体如下:

类内声明

template<typename = std::enable_if_t<supports::less_than<T>::value, int>>
bool insert_sorted(const value_type& val);

类外实现

template<typename T>
template<typename Dummy> // 参数名可任意,仅用于匹配声明的模板参数
bool PtrVector<T>::insert_sorted(const value_type& val)
{
    auto it = std::lower_bound(begin(), end(), val, [](const value_type& a, const value_type& b)->bool { return *a < *b; });

    if (it == end() || *val < *(*it))
    {
        m_container.insert(it, val);
        return true;
    }
    return false;
}

解释

  1. 类内的insert_sorted是一个成员模板,带有一个默认模板参数(利用std::enable_if_t实现SFINAE,仅当S支持operator<()时才会实例化该函数)。
  2. 类外定义时,必须先写类的模板参数template<typename T>,再写成员的模板参数template<typename Dummy>,这样才能和类内的声明匹配。
  3. 成员模板的参数名(这里的Dummy)不影响功能,因为调用时会使用默认参数,无需显式指定。

额外优化:简化类型检查(可选)

C++17提供了std::is_invocable_r,可以替代手写的supports::less_than,代码更简洁且可读性更高:

// 替换原有的supports::less_than
template<typename T>
constexpr bool has_less_than_v = std::is_invocable_r_v<bool, decltype(&operator<), const std::remove_pointer_t<T>&, const std::remove_pointer_t<T>&>;

之后在enable_if中直接使用has_less_than_v<T>即可。


内容的提问来源于stack exchange,提问作者marcbf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 19:38:08