C++11 C++;:使用参数包使用变量类型参数的模板类继承

C++11 C++;:使用参数包使用变量类型参数的模板类继承,c++11,templates,inheritance,C++11,Templates,Inheritance,(我不知道如何命名这个问题,也找不到类似的问题。如果这是重复的,很抱歉) 如果我想从某个基本模板类继承,我可以这样做: template<typename A=int, typename B=char> class C {}; template<typename... Args> class D : public C<Args...> {}; //it works! 模板类C{}; 模板类D:公共C{}//它起作用了! 通过这种方式,我可以更改项目传递给模

(我不知道如何命名这个问题,也找不到类似的问题。如果这是重复的,很抱歉)

如果我想从某个基本模板类继承,我可以这样做:

template<typename A=int, typename B=char> class C {};
template<typename... Args> class D : public C<Args...> {}; //it works!
模板类C{};
模板类D:公共C{}//它起作用了!
通过这种方式,我可以更改项目传递给模板类C的参数,而不必更改类D的所有用法。太好了。但如果我的模板类不仅使用类型作为参数,还使用值呢?例如:

template<int dim=3, typename float_t=double> class GeometricObject{};
template<typename... Args> class Point : public GeometricObject<Args...>{}; //it doesnt work
模板类GeometricObject{};
模板类点:公共几何对象{}//它不起作用
当然,我可以在开头用整数类型定义最后一个模板。但这不是一种方法,如果我有100个不同的类都继承自GeometricObject,然后我将默认值
dim
更改为2,那么我必须更改每个类的定义


我还希望有一种方法可以避免使用任何
\define
\else
和类似的预处理器命令。我知道模板实际上也是预处理器命令,但是。。。好吧,让我们在这里现代一点;)

不能在模板参数包中混合使用类型参数和非类型参数。但是您的
和其他派生类似乎不需要单独访问参数包参数。在这种情况下,传递基类更容易,而且语义更正确:

template<int dim=3, typename float_t=double> class GeometricObject{};
template<class GeometricObject=GeometricObject<>> class Point : public GeometricObject{};
当然,
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{};
模板
结构几何对象{
使用Base=GeometricObject;
使用点=::点;
// ...
};
使用TwoDim=几何对象;
点a{};

我假设您有多个模板类,并且希望您的
对象能够从所有模板类继承

而不是做:

template <typename ... Args>
class Point : public GeometricObject<Args...>{};
主要场景:
的方法需要
几何对象
的类型模板参数(将它们转发到
几何对象
的方法)。要实现这一点,您必须传入一个
元组
,该元组将展开以调用内部方法。为此,我利用了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);
    }
};
模板
课点:公共T{
模板

自动调用展开(Method,std::tuple

好的,所以我想出了应该如何将变量类型模板参数包含到tuple中。基本上,我需要将它们“封装”到新参数中。此示例运行良好,解决了我的问题:

#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

}
#包括
模板结构尺寸{
常数int dim=n;
};
模板类SillyBaseClass{
公众:
typedef typename T dim;
};
模板类SillyDerivedClass:公共SillyBaseClass{
公众:
typedef typename SillyBaseClass::dim;
SillyDerivedClass(){
静态断言(std::is_same::value,
“尺寸数量必须等于2”);
}
};
int main(){
SillyDerivedClass Class2d;//这很有效
SillyDerivedClass Class3d;//返回预期错误
}

您的值参数是否与类型参数分开,即值参数是否总是像此
模板
?可能是这样。如果我不知道一般答案,那么具体答案也很好:)你不能直接传递专门的模板并使用适当的typedef访问参数包吗?例如,我不是很好的模板弯曲器。这是什么魔法。我认为使用
语句是C#的领域。谢谢你的回答!
使用TwoDim=GeometricObjects
typedef Geome是一样的tricObjects TwoDim
,更“现代”-哪一部分看起来像魔法?我很乐意详细说明。只是使用< < /Cord>语句>使用变量的类型。这几乎就像在C++中找到Python一样的智能快捷方式。谢谢改进。我将下面的文本改为它。这里是<<代码>的链接,使用语法。回答。看起来我没有选择,如果我想弄乱模板,我需要生成更复杂的代码。谢谢!:)
template <typename T>
struct type_parameters;

template <int N, typename Float>
struct type_parameters<GeometricObject<N, Float> {
    typedef std::tuple<Float> types;
};
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);
    }
};
#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

}