(我不知道如何命名这个问题而我找不到类似的东西。抱歉,如果这是重复的话)
如果我想继承一些基本模板类,我可以这样做:
template<typename A=int, typename B=char> class C {};
template<typename... Args> class D : public C<Args...> {}; //it works!
这样我可以将项目传递的参数更改为模板类C,而且我不必更改D类的每个用法。很棒。但是如果我有模板类不仅使用类型作为参数而且还使用值?例如:
template<int dim=3, typename float_t=double> class GeometricObject{};
template<typename... Args> class Point : public GeometricObject<Args...>{}; //it doesnt work
当然我可以在开头定义最后一个带整数类型的模板。但这不是一种方法,如果我有100个不同的类都继承自GeometricObject,然后我将默认的dim
值更改为2,我将不得不更改每个类的定义。
我也希望不使用任何#define
,#else
和类似的预处理器命令。我知道模板实际上也是预处理器命令,但是......好吧,让我们现代化;)
答案 0 :(得分:4)
您不能在模板参数包中混合使用type和non-type参数。但似乎您的Point
和其他派生类不需要单独访问参数包参数。在这种情况下,传递基类更容易,也更语义正确:
template<int dim=3, typename float_t=double> class GeometricObject{};
template<class GeometricObject=GeometricObject<>> class Point : public GeometricObject{};
实例化Point
可能如下所示:
Point<> a{}; // the same as Point<GeometricObject<>> a{};
Point<GeometricObject<4>> b{};
Point<GeometricObject<2, float>> c{};
当然,GeometricObject<...>
可以是更短的类型。此外,它可以看起来像命名空间,而不是分别为每个几何对象提供参数:
template<int dim = 3, typename float_t = double>
struct GeometricObjects {
using Base = GeometricObject<dim, float_t>;
using Point = ::Point<Base>;
// ...
};
using TwoDim = GeometricObjects<2>;
TwoDim::Point a{};
答案 1 :(得分:2)
我想你有多个模板类,你希望你的Point
对象能够从它们全部继承。
而不是:
template <typename ... Args>
class Point : public GeometricObject<Args...>{};
我会改为:
template <typename T>
class Point : public T {};
现在我们只需定义适当的特征即可在需要时访问类型模板参数。这些类型应该计入std::tuple
(例如)。
填补此特征的负担在GeometricObject
课程上。例如,根据您的定义,我们将:
template <typename T>
struct type_parameters;
template <int N, typename Float>
struct type_parameters<GeometricObject<N, Float> {
typedef std::tuple<Float> types;
};
主要方案:Point
的方法需要GeometricObject
的类型模板参数(将它们转发给GeometricObject
的方法)。要实现这一点,您必须传入一个tuple
来展开调用内部方法。为此,我使用了STL for C ++ 14中添加的功能。你仍然可以自己重写它们,但我免除了这个问题的麻烦......
template <typename T>
class Point : public T {
template <typename Method, typename ... Args, std::size_t ... Is>
auto call_unfold(Method method, std::tuple<Args...> const& tuple, std::integer_sequence<std::size_t, Is...>) {
return (this->*method)(std::get<Is>(tuple)...);
}
template <typename Method, typename Tuple>
auto call_unfold(Method method, Tuple const& tuple) {
return call_unfold(method, tuple, std::make_index_sequence<std::tuple_size<Tuple>::value>());
}
public:
typedef typename type_parameters<T>::types types;
void some_method(types const& args) {
return call_unfold(&T::some_method, args);
}
};
这个例子没有什么意义,但是同样的技术对于需要调用基类构造函数的Point
构造函数很有用。
答案 2 :(得分:0)
好的,所以我想出了如何将变量类型的模板参数包含到元组中。基本上我需要将它们“封装”到新参数中。这个例子非常好用并解决了我的问题:
#include <type_traits>
template<int n = 2> struct Dim {
const int dim = n;
};
template<typename T> class SillyBaseClass {
public:
typedef typename T dim;
};
template<typename... Args> class SillyDerivedClass : public SillyBaseClass<Args...>{
public:
typedef typename SillyBaseClass::dim dim;
SillyDerivedClass() {
static_assert(std::is_same<dim,Dim<2>>::value,
"Number of dimensions must be equal to 2");
}
};
int main() {
SillyDerivedClass<Dim<2>> Class2d; //this works
SillyDerivedClass<Dim<3>> Class3d; //this returns expected error
}