如何在容器类型上建立模板



我有两个函数

template <class T> void foo(std::vector<T>* p)

template <class T> void foo(std::valarray<T>* p)

函数体中的代码是相同的。有没有一种巧妙的方法来编写模板,这样我就可以避免重复?类似的东西

template <class T, class Container> void foo(Container<T>* p)

我正在使用C++14。

我只希望允许Containerstd::vectorstd::valarray

您也可以只为您的案例创建类型特征。

template <typename T>
struct is_vector_or_valarray : std::false_type {};
template<class T>
struct is_vector_or_valarray<std::vector<T>> : std::true_type {};
template<class T>
struct is_vector_or_valarray<std::valarray<T>> : std::true_type {};
template<typename C, typename = std::enable_if_t<is_vector_or_valarray<C>::value>>
void foo(C* p) {}

演示


如果您希望允许传入从std::vectorstd::valarray派生的类。

template<template<typename...> typename T, typename U>
struct is_tbase_of
{
private:
template<class V>
static std::pair<V, decltype(static_cast<const T<V>&>(std::declval<U>()), std::true_type{})> test(const T<V>&);
static std::pair<U, std::false_type> test(...);
public:
using _aux_type = decltype(test(std::declval<U>()));
using base_type = T<typename _aux_type::first_type>;
static constexpr bool value = _aux_type::second_type::value;
};

template<typename C,
typename = std::enable_if_t<
is_tbase_of<std::vector, C>::value
|| is_tbase_of<std::valarray, C>::value>>
void foo(C* p) {
using base_t = std::conditional_t<
is_tbase_of<std::vector, C>::value,
typename is_tbase_of<std::vector, C>::base_type,
typename is_tbase_of<std::valarray, C>::base_type>;
auto pbase = static_cast<base_t*>(p);
// operate on pbase
}

用于检查类是否从模板类继承的类型特征来自这个答案。我在此基础上做了一些细微的更改(主要是为了获得基本类型)。

正如@Raymond所说,c应该被强制转换为其基指针,以便对切片部分进行操作。我认为它应该在函数体中完成,否则,会有一个非推导的上下文。

演示

注意:你不能真正专门研究std::vector<>std::valarray<>,但你可以说,对于给定的(推导的)T,你期望std::vector<T>std::valarray<T>。因此,别名也将被解析。

诀窍是,为模板类C和类型T(以及可能的其他参数,如std中的参数)临时化,然后使用仅在std::vector<T>std::valarray<T>解析时解析(在这种情况下为空)的std::enable_if<>

另外请注意,您可能希望允许自定义分配器等,也就是说,建议对容器使用typename... Ts,而不是单个T。

#include <iostream>
#include <vector>
#include <valarray>
#include <type_traits>
template<template<class...> class C, typename T>
auto foo(C<T>* arg) -> std::enable_if_t<std::is_same<C<T>, std::vector<T>>::value || std::is_same<C<T>, std::valarray<T>>::value>
{
}
int main() {
std::vector<int> v;
std::valarray<int> va;
//std::pair<int, int> p; // this should fail
foo(&v);
foo(&va);
//foo(&p); // this fails as expected
return 0;
}

如果您还想处理派生类,可以使用std::is_base_of<>,但对于std命名空间中的类,不建议从它们派生。

相关内容

  • 没有找到相关文章

最新更新