如何在 C++ 中设计库包装器?

How to design a library wrapper in C++?

我想用简单的语法在 C++ 中设计一个包装器:

Vector<double,stl> v; // aka std::vector<double>
Vector<double, eigen> w; // aka Eigen::VectorXd from Eigen library
Matrix<double, eigen> m; // aka Eigen::MatrixXd from Eigen library

但是,我无法理解这种语法,尤其是最后两个示例。这是我的代码,用于包装 STL 向量的情况:

#ifndef WRAPPER_HPP
#define WRAPPER_HPP

#include <cstdlib>
#include <vector>

//=============
// BASE WRAPPER
//=============

template<class ScalarType, template<class,class...> class WrappedType>
class Wrapper
{
protected:
  WrappedType<ScalarType> wrapped_;
};

//==============
// STL WRAPPER
//==============

template<class ScalarType, template<class,class...> class WrappedType>
struct stl;

template<class ScalarType>
struct stl<ScalarType,std::vector> : public Wrapper<ScalarType,std::vector>
{
public:
  size_t size()
  { return this->wrapped_.size(); }
};

//=======
// VECTOR
//=======
template<class ScalarType, template<class, template<class,class...> class> class Wrapper>
using Vector = Wrapper<ScalarType,std::vector>;
// **** Problem : I should not provide "std::vector" above ****

#endif

STL 包装器是一种名为 stl 的结构。这个结构实际上是Wrapperclass的subclass。我有专门用于 STL 向量的 stl 结构。我可能会为某些容器(列表、地图等)做一些其他的专业化。因此,当声明

Vector<double,stl> vec

我希望能够从对 (Vector, stl) 中推断出它对应于 std::vector 的 stl 特化。但是,我做不到。每次尝试时,我都会对模板参数进行无限递归。

可能有一个使用 typedef 或模板别名执行此操作的好方法,但我找不到它。可能是这样的:

template<class ScalarType, template<class, template<class,class...> class> class Wrapper>
using Vector = Wrapper<ScalarType,????>;

在哪里????将等同于 std::vector,但从 Wrapper 推导出来。但是不知道可不可以。

我的设计也可能很幼稚。我真的很感激任何改进它的建议。我只对代码的语法感兴趣。

谢谢!

使用 C++11 或更高语法,这很容易做到。

这是一个实现 Vector 包装器的示例,它将生成您正在寻找的语法。使用类似的方法实现Matrix

该方法将模板特化与 template using 相结合,选择正确的特化来声明一个成员类型,该成员类型是被声明的实际类型:

#include <vector>

class stl; // dummy class
class eigen; // dummy class

template<typename ...Args> class vector_impl;

template<>
class vector_impl<double, stl> {

public:
    typedef std::vector<double> impl_type;
};

template<>
class vector_impl<double, eigen> {

public:
    typedef Eigen::VectorXd impl_type;   // I presume...
};

// And the magical alias:

template<typename ...Args>
using Vector=typename vector_impl<Args...>::impl_type;

以上定义:

Vector<double, stl> a;    // This declares a std::vector<double>
Vector<double, eigen> b;  // This declares an `Eigen::VectorXd`

使用可变参数模板可以进行一些进一步的工作,即一些额外的调整也可以产生一些额外的效果,比如将自定义分配器类型转发到 std::vector,等等...