构造函数、模板和非类型参数
Constructors, templates and non-type parameters
我有一个类,由于某些原因必须依赖于int
模板参数。
出于同样的原因,该参数不能是类的参数列表的一部分,而是其构造函数的参数列表的一部分(当然,是模板化的)。
这里出现了问题。
也许我错过了一些东西,但我看不到向构造函数提供这样一个参数的简单方法,因为它无法推断或显式指定。
到目前为止,我找到了以下替代方案:
-
将上面提到的参数放入类的参数列表中
-
创建一个工厂方法或工厂函数,可以作为示例调用
factory<42>(params)
-
为构造函数提供特征结构
我试图为最后提到的解决方案创建一个(不是那么)最小的工作示例,也是为了更好地解释这个问题。
示例中的类不是自身的模板类,因为关键点是构造函数,无论如何,真正的类是模板类。
#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();
}
老实说,上述解决方案都不适合:
将参数移动到类的参数列表中会完全破坏其设计,并且不是一个可行的解决方案
工厂方法是我想避免的,但它可以解决问题
特征结构似乎是迄今为止最好的解决方案,但不知何故我并不完全满意
问题很简单:我是否错过了一些东西,也许是一个更简单、更优雅的解决方案,一个我完全忘记的语言细节,或者上面提到的三种方法是我必须选择的方法?
任何建议将不胜感激。
你必须传递一些可以推断的东西。最简单的使用方法只是一个 int: std::integral_constant
的空包装器。由于您只想要我相信int
s,我们可以为其别名,然后仅接受该特定类型:
template <int N>
using int_ = std::integral_constant<int, N>;
您的C
构造函数只是接受这一点:
template <int N>
explicit C(int_<N> ) {
b = new D<N>{};
}
C c{int_<3>{}};
你甚至可以全力以赴,为此创建一个用户定义的文字(一个 la Boost.Hana),这样你就可以编写:
auto c = 3_c; // does the above
<小时 />此外,请考虑简单地将特征转发到 D
.如果任何地方的所有东西都是一种类型,那么元编程效果会更好。也就是说,仍然接受C
中相同的int_
:
template <class T>
explicit C(T ) {
b = new D<T>{};
}
现在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;
};
从用户的角度来看,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>
C c{new C::D<N>()};
// this variable should be rather const - but foo() is not const
// and copy semantic is not implemented...
和用法:
int main() {
// you did not implement copy semantic properly - so just reference taken
C& c = ::c<3>;
c.foo();
}
- 具有基类的解决方案 - 并根据
int
派生类
这个解决方案,虽然看起来很有前途,但我个人会避免 - 这只会使设计复杂化 - 并且这里也存在一些对象切片的可能性。
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();
}
问:人们可以问,使用基类的解决方案比仅将int
添加为另一个参数更好。
答:通过基本实现类,您不需要拥有相同代码的许多"副本" - 您可以避免模板代码膨胀...
使用模板专用化和继承:
#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; }
- C++:使用运算符 = 调用多参数构造函数
- 有没有办法避免为 std::variant 类成员中的所有类型编写构造函数?
- 在 C++17 中调用具有不同参数类型的构造函数
- 无法推断类中的类型,构造函数采用 std::array
- 通过零参数构造函数创建的 glm::mat4 应该包含哪些值?
- 如何重载相同类型的构造函数?
- 如何构造一个类型特征,可以判断一个类型的私有方法是否可以在另一个类型的构造函数中调用?
- 如何避免具有相同类型参数的函数中的错误
- 好奇的混合与可变参数构造函数
- 具有默认值的单个参数构造函数是否与默认构造函数相同?
- 两种类型的构造函数重载
- 为什么我们需要创建一个单参数构造函数来使用临时的无名称对象
- 内置类型的构造函数初始化
- 在可变参数构造函数中初始化常量数组
- 如何在派生类上强制实现特定数据类型的构造函数?
- C++ 显式多参数构造函数歧义
- 确保模板参数类型与其可变参数构造函数的类型匹配
- 将具有可选模板类型参数的函数传递给类构造函数并将其分配给方法
- C 不能将父类型用作构造函数中的参数
- 用给定的类型和构造函数参数创建和销毁临时函数的c++函数