构造函数,模板和非类型参数

sky*_*ack 17 c++ templates constructor software-design traits

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

这里出现了问题.
也许我错过了一些东西,但是我看不到向构造函数提供这样一个参数的简单方法,因为它不能推断也不能明确指定.

到目前为止,我发现了以下替代方案:

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

  • 创建工厂方法或工厂函数,可以作为示例调用 factory<42>(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();
}
Run Code Online (Sandbox Code Playgroud)

说实话,上面提到的解决方案都不合适:

  • 将参数移动到类的参数列表中会完全破坏其设计并且不是可行的解决方案

  • 工厂方法是我想避免的,但它可以解决问题

  • 到目前为止,traits struct似乎是最好的解决方案,但不知怎的,我并不完全满意

问题很简单:有没有我错过的东西,可能是一个更容易,更优雅的解决方案,我完全忘记的语言细节,或者上面提到的三种方法我必须选择哪种方法?
任何建议将不胜感激.

Bar*_*rry 7

你必须传递一些可以推断出来的东西.最简单的方法是使用int的空包装器std::integral_constant.既然你只想要int我相信,我们可以使用别名,然后只接受特定的类型:

template <int N>
using int_ = std::integral_constant<int, N>;
Run Code Online (Sandbox Code Playgroud)

你的C构造函数只接受:

 template <int N>
 explicit C(int_<N> ) {
     b = new D<N>{};
 }

 C c{int_<3>{}};
Run Code Online (Sandbox Code Playgroud)

您甚至可以全力以赴为此创建一个用户定义的文字(la Boost.Hana),以便您可以编写:

auto c = 3_c; // does the above
Run Code Online (Sandbox Code Playgroud)

另外,考虑简单地将特征转发到D.如果所有地方都是一种类型,元编程会更好地工作.也就是说,仍然接受相同int_C:

template <class T>
explicit C(T ) {
    b = new D<T>{};
}
Run Code Online (Sandbox Code Playgroud)

现在D需要的东西有::value:

template <class T>
struct D: public B{
    static constexpr int N = T::value;

    void foo() {
        using namespace std;
        cout << N << endl;
    }

    std::array<int, N> arr;
};
Run Code Online (Sandbox Code Playgroud)

从用户C的角度来看,这是一回事,但值得一想.