我有一个容器模板类,它内部聚合了类型为
std::vector
的 T
,其中 T
实际上是指向 S
类型的指针。我想创建一个成员函数 insert_sorted()
,只有当 S
、T
指向的类型实际上支持 operator<()
时才会实现该函数。
可悲的是,除了基本的东西之外,我不太熟悉模板,而且类型特征对我来说也是一个未知的国家。我一直在 SO 和互联网上其他地方查看许多类似的问题,但我太笨了,无法找出正确的语法。看来我需要使用
std::enable_if
,但是如何呢?理想情况下,我希望将声明和实现分开。有人可以帮忙吗?顺便说一句,我正在 C++17 中使用 MSVC 2022。
这是类的声明(删除了一些不必要的东西)。除了
insert_sorted()
之外的所有内容都可以编译并运行:
#include <vector>
#include <algorithm>
#include <type_traits>
#include <utility>
#include <assert.h>
// Disable warning 'C4251': class 'type1' needs to have dll-interface to be used by clients of class 'type2'
// Disable warning 'C4275': non dll-interface class used as base for dll-interface class
#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;
};
// PtrVector implementation
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>, 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>, int>>
bool insert_sorted(const value_type& val);
template<typename T, typename = std::enable_if_t<supports::less_than<T>, 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;
}
因为
insert_sorted()
是一个嵌套模板,所以你需要2个template
来实现它,例如:
template<typename T>
template<typename = std::enable_if_t<supports::less_than<T>, 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;
}