C++ 构造函数、模板和非类型参数

C++ 构造函数、模板和非类型参数,c++,templates,constructor,traits,software-design,C++,Templates,Constructor,Traits,Software Design,由于某些原因,我有一个类必须依赖于int模板参数。 出于同样的原因,该参数不能是类的参数列表的一部分,而是其构造函数的参数列表的一部分(当然是模板化的) 问题就出现了。 也许我遗漏了一些东西,但我看不到一个简单的方法来向构造函数提供这样一个参数,因为它既不能推导也不能显式指定 到目前为止,我已经找到了以下替代方案: 将上述参数放入类的参数列表中 创建一个工厂方法或工厂函数,该方法或函数可以被调用,例如factory(params) 为构造函数提供一个traits结构 我试图为最后提到的解决方

由于某些原因,我有一个类必须依赖于
int
模板参数。
出于同样的原因,该参数不能是类的参数列表的一部分,而是其构造函数的参数列表的一部分(当然是模板化的)

问题就出现了。
也许我遗漏了一些东西,但我看不到一个简单的方法来向构造函数提供这样一个参数,因为它既不能推导也不能显式指定

到目前为止,我已经找到了以下替代方案:

  • 将上述参数放入类的参数列表中

  • 创建一个工厂方法或工厂函数,该方法或函数可以被调用,例如
    factory(params)

  • 为构造函数提供一个traits结构

我试图为最后提到的解决方案创建一个(并非如此)最小的工作示例,也是为了更好地解释问题。
示例中的类本身不是模板类,因为关键点是构造函数,不管怎样,真正的类是模板类

#include<iostream>
#include<array>

template<int N>
struct traits {
    static constexpr int size = N;
};

class C final {
    struct B {
        virtual ~B() = default;
        virtual void foo() = 0;
    };

    template<int N>
    struct D: public B{
        void foo() {
            using namespace std;
            cout << N << endl;
        }

        std::array<int, N> arr;
    };

 public:
     template<typename T>
     explicit C(T) {
         b = new D<T::size>{};
     }

     ~C() { delete b; }

     void foo() { b->foo(); }

 private:
     B *b;
};

int main() {
    C c{traits<3>{}};
    c.foo();
}
#包括
#包括
模板
结构特征{
静态constexpr int size=N;
};
丙级决赛{
结构B{
virtual~B()=默认值;
虚拟void foo()=0;
};
模板
结构D:公共B{
void foo(){
使用名称空间std;
cout您必须传入可以推断的内容。最简单的方法是使用int的空包装:。因为我相信您只需要
int
s,所以我们可以将其别名,然后只接受该特定类型:

template <int N>
using int_ = std::integral_constant<int, N>;
您甚至可以全力以赴,为此创建一个用户定义的文本(la Boost.Hana),以便编写:

auto c = 3_c; // does the above

也可以简单地将特性转发到<代码> d>代码>。如果所有的事物都是一种类型,元编程效果更好。也就是说,在<代码> c>代码>:

中,仍然接受相同的<代码>
template <class T>
explicit C(T ) {
    b = new D<T>{};
}

C
用户的角度来看,这两种方法都是一样的,但值得一想。

我认为,在大多数情况下,带有“特征”的解决方案是最好的

只是为了在这个问题上制造更多的“混乱”,我将提供另外两种选择。也许在一些非常具体的情况下,它们可以在某种程度上更好


  • 模板全局变量-您可以将其命名为原型解决方案:
  • C
    仅在构造函数上与原始代码不同:

    class C final {
        // All B and D defined as in OP code
     public:
        // Here the change - c-tor just accepts D<int> 
        template <int size>
        explicit C(D<size>* b) : b(b) {}
    
        // all the rest as in OP code
    };
    
    然后-最后一节课:

    template <int N>
    class C final : private CBase {
    public:
        C() : CBase(new CBase::D<N>()) {}
        using CBase::foo;
    };
    
    模板
    C类期末考试:私人CBase{
    公众:
    C():CBase(新的CBase::D()){}
    使用CBase::foo;
    };
    
    用法:

    int main() {
        C<3> c;
        c.foo();
    }
    
    intmain(){
    C C;
    c、 foo();
    }
    
    Q:人们可以问,使用基类的解决方案比仅仅添加
    int
    作为另一个参数要好。

    A:根据基本实现类,您不需要有许多相同代码的“副本”-您可以避免模板代码膨胀…

    使用模板专门化和继承:

    #include <iostream>
    using namespace std;
    
    template <int num> struct A {
        A() { cout << "generic" << endl; }
    };
    
    template <> struct A<1> {
        A() { cout << "implementation of 1" << endl; }
    };
    
    template <int num>
    struct B : public A<num> {
        B() : A<num>() {}
    };
    
    int main(int argc, char *argv[])
    {
        B<1> b;
        B<3> b1;
        B<4> b2;
    }
    
    #包括
    使用名称空间std;
    模板结构A{
    
    A(){可以推断,但是是的,您需要一个标记类型-例如,
    template explicit C(traits);
    (其中
    traits
    可以是
    template using traits=std::integral_constant;
    )是的,这几乎就是我所做的。无论如何,如果我必须引入一个traits类,我还可以用它来定义其他一些东西,这就是为什么我没有使用像
    积分常量
    这样的东西。在你的第一段中,你说它既是模板参数又是构造函数的参数,这是没有意义的。或者这是非常重要的吗矛盾让你困惑?我的意思是,如果它很容易推断,它将成为构造函数模板声明的参数列表的一部分,就像
    模板构造函数(不管你想要什么)
    。我不是100%清楚你在问什么,但是有没有什么类型的擦除技巧可以帮助你?
    int main() {
        // you did not implement copy semantic properly - so just reference taken
        C& c = ::c<3>; 
        c.foo();
    }
    
    class CBase {
        // all here as in OP code for C class
    public:
        // only difference is this constructor:
        template<int size>
        explicit CBase(D<size>* b) : b(b) {}
    };
    
    template <int N>
    class C final : private CBase {
    public:
        C() : CBase(new CBase::D<N>()) {}
        using CBase::foo;
    };
    
    int main() {
        C<3> c;
        c.foo();
    }
    
    #include <iostream>
    using namespace std;
    
    template <int num> struct A {
        A() { cout << "generic" << endl; }
    };
    
    template <> struct A<1> {
        A() { cout << "implementation of 1" << endl; }
    };
    
    template <int num>
    struct B : public A<num> {
        B() : A<num>() {}
    };
    
    int main(int argc, char *argv[])
    {
        B<1> b;
        B<3> b1;
        B<4> b2;
    }
    
    template <int num>
    struct A {
        A();
    };
    
    template <int num>
    A<num>::A() { cout << "general " << num << endl; }
    
    template <>
    A<1>::A() { cout << "specialization for 1" << endl; }