构造函数、模板和非类型参数
Constructors, templates and non-type parameters
我有一个 class 由于某些原因必须依赖于 int
模板参数。
出于同样的原因,该参数不能是 class 的参数列表的一部分,而是其构造函数(当然是模板化)的参数列表的一部分。
问题就出在这里
也许我遗漏了一些东西,但我看不到向构造函数提供这样一个参数的简单方法,因为它既不能推导也不能明确指定。
到目前为止,我找到了以下替代方案:
将上述参数放入class
的参数列表中
创建一个工厂方法或工厂函数,可以作为示例调用 factory<42>(params)
为构造函数提供一个traits结构
我试图为最后提到的解决方案创建一个(不是那么)最小的工作示例,也是为了更好地解释问题。
例子中的class本身不是模板class,关键是构造函数,反正真正的是模板class.
#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();
}
老实说,上面提到的 none 个解决方案很适合:
将参数移动到 class 的参数列表中完全破坏了它的设计并且不是一个可行的解决方案
我想避免使用工厂方法,但它可以解决问题
traits 结构似乎是迄今为止最好的解决方案,但不知何故我并不完全满意
问题很简单:有没有我遗漏的东西,也许是更简单、更优雅的解决方案,我完全忘记的语言细节,或者我必须选择上面提到的三种方法?
如有任何建议,我们将不胜感激。
你必须传入可以推断的东西。最简单的使用方法就是对 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>{}};
你甚至可以全力以赴为此创建一个用户定义的文字(a 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
的用户角度来看,这两种方式都是一样的,但值得深思。
我认为 "traits" 的解决方案对大多数情况来说是最好的。
只是为了多做一点"mess"这一期我再提供两个备选方案。也许在某些非常具体的情况下 - 它们可以在某些方面更好。
- 模板全局变量 - 您可以将其命名为 原型解决方案:
class 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();
}
- 基于 class 的解决方案 - 并根据
int
导出 class
这个解决方案虽然看起来很有前途,但我个人会避免 - 这只会使设计复杂化 - 并且这里也存在对象切片的一些可能性。
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) {}
};
然后-决赛class:
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();
}
问: 可以问 Base class 的解决方案比只添加 int
作为另一个参数。
A: 通过基础实现 class 你不需要很多 "copies" 相同的代码 - 你可以避免模板代码膨胀...
使用模板专业化和继承:
#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; }
我有一个 class 由于某些原因必须依赖于 int
模板参数。
出于同样的原因,该参数不能是 class 的参数列表的一部分,而是其构造函数(当然是模板化)的参数列表的一部分。
问题就出在这里
也许我遗漏了一些东西,但我看不到向构造函数提供这样一个参数的简单方法,因为它既不能推导也不能明确指定。
到目前为止,我找到了以下替代方案:
将上述参数放入class
的参数列表中
创建一个工厂方法或工厂函数,可以作为示例调用
factory<42>(params)
为构造函数提供一个traits结构
我试图为最后提到的解决方案创建一个(不是那么)最小的工作示例,也是为了更好地解释问题。
例子中的class本身不是模板class,关键是构造函数,反正真正的是模板class.
#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();
}
老实说,上面提到的 none 个解决方案很适合:
将参数移动到 class 的参数列表中完全破坏了它的设计并且不是一个可行的解决方案
我想避免使用工厂方法,但它可以解决问题
traits 结构似乎是迄今为止最好的解决方案,但不知何故我并不完全满意
问题很简单:有没有我遗漏的东西,也许是更简单、更优雅的解决方案,我完全忘记的语言细节,或者我必须选择上面提到的三种方法?
如有任何建议,我们将不胜感激。
你必须传入可以推断的东西。最简单的使用方法就是对 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>{}};
你甚至可以全力以赴为此创建一个用户定义的文字(a 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
的用户角度来看,这两种方式都是一样的,但值得深思。
我认为 "traits" 的解决方案对大多数情况来说是最好的。
只是为了多做一点"mess"这一期我再提供两个备选方案。也许在某些非常具体的情况下 - 它们可以在某些方面更好。
- 模板全局变量 - 您可以将其命名为 原型解决方案:
class 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();
}
- 基于 class 的解决方案 - 并根据
int
导出 class
这个解决方案虽然看起来很有前途,但我个人会避免 - 这只会使设计复杂化 - 并且这里也存在对象切片的一些可能性。
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) {}
};
然后-决赛class:
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();
}
问: 可以问 Base class 的解决方案比只添加 int
作为另一个参数。
A: 通过基础实现 class 你不需要很多 "copies" 相同的代码 - 你可以避免模板代码膨胀...
使用模板专业化和继承:
#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; }