整数常量与类型的偏特化
Partial Specialization for an Integral Constant vs a Type
是否可以根据模板参数是类型还是整数常量来特化模板?这是一个无法编译但说明意图的示例:
#include <cstdio>
#include <cstddef>
// tag struct
struct DynamicSize {};
template<class T, class Size>
class Container;
template<class T>
class Container<T, DynamicSize>
{
public:
Container() {
std::puts("dynamic size");
}
};
template<class T, int Size>
class Container<T, Size>
{
public:
Container() {
std::puts("static size");
}
};
int main(int argc, char* argv[]) {
Container<char, 20> a;
Container<char, DynamicSize> b;
}
Eigen 库支持固定大小或运行时确定大小的矩阵,并执行与此类似的操作。那里的实现是模板参数始终是一个整型常量,动态标记只是一个等于 -1 的常量,但我很好奇是否还有其他方法。
我认为唯一的方法是让 Container
模板采用 Size
的类型参数。然后由类型负责处理它是动态的还是静态的。我认为任何特定于存储类型类型的细节都可以限制在 struct
类型中。也许下面的例子会有所帮助。
示例代码
#include <iostream>
struct DynamicSize
{
static const int size = -1;
};
template<int Size>
struct FixedSize
{
static const int size = Size;
};
template<class T, class Size>
class Container
{
public:
Container()
{
std::cout << Size::size << "\n";
}
};
int main()
{
Container<char, FixedSize<20>> a;
Container<char, DynamicSize> b;
return 0;
}
示例输出
20
-1
James 提出的解决方案非常好!
但是,如果确实需要部分专业化,正如问题最初的要求(例如,为了实现不同的行为在这两种不同的情况下),根据詹姆斯的回答,我建议:
#include <iostream>
struct DynamicSize {};
template<int Size>
struct FixedSize {};
template<class T, class Size>
class Container;
template<class T, int size>
class Container<T, FixedSize<size>> {
public:
Container() { std::cout << "FixedSize: " << size << "\n"; }
};
template<class T>
class Container<T, DynamicSize> {
public:
Container() { std::cout << "dynamic size\n"; }
};
// you can also do that
template<class T>
class Container<T, FixedSize<0>> {
public:
Container() { std::cout << "Special case of FixedSize 0\n"; }
};
int main() {
Container<char, FixedSize<20>> a;
Container<char, DynamicSize> b;
Container<char, FixedSize<0>> c;
}
示例输出
FixedSize: 20
dynamic size
Special case of FixedSize 0
但为什么要到此为止呢?
如果需要专注于大小本身(即为不同的固定大小值创建不同的实现,通过预定义范围选择),一个可以做到:
enum class SIZE_RANGE {SMALL, MEDIUM = 10, BIG = 100};
constexpr bool operator<(int size, SIZE_RANGE s) {
return size < (int)s;
}
//------------------------------------------------------------------------------------
// FixedSize manages its own range selection here
template<int Size,
SIZE_RANGE SizeRange = (Size < SIZE_RANGE::MEDIUM? SIZE_RANGE::SMALL :
Size < SIZE_RANGE::BIG? SIZE_RANGE::MEDIUM :
SIZE_RANGE::BIG)>
struct FixedSize {};
//------------------------------------------------------------------------------------
现在我们可以根据其范围专门研究 Container 的大小:
template<class T, class Size>
class Container;
template<class T>
class Container<T, FixedSize<0>> {
public:
Container() { std::cout << "Special case of FixedSize 0\n"; }
};
template<class T, int size>
class Container<T, FixedSize<size, SIZE_RANGE::SMALL>> {
public:
Container() { std::cout << "Small FixedSize: " << size << "\n"; }
};
template<class T, int size>
class Container<T, FixedSize<size, SIZE_RANGE::MEDIUM>> {
public:
Container() { std::cout << "Medium FixedSize: " << size << "\n"; }
};
template<class T, int size>
class Container<T, FixedSize<size, SIZE_RANGE::BIG>> {
public:
Container() { std::cout << "Big FixedSize: " << size << "\n"; }
};
template<class T>
class Container<T, DynamicSize> {
public:
Container() { std::cout << "dynamic size\n"; }
};
主要可以通过以下方式进行演示:
int main() {
Container<char, DynamicSize> a;
Container<char, FixedSize<0>> b;
Container<char, FixedSize<5>> c;
Container<char, FixedSize<42>> d;
Container<char, FixedSize<100>> e;
}
示例输出
dynamic size
Special case of FixedSize 0
Small FixedSize: 5
Medium FixedSize: 42
Big FixedSize: 100
是否可以根据模板参数是类型还是整数常量来特化模板?这是一个无法编译但说明意图的示例:
#include <cstdio>
#include <cstddef>
// tag struct
struct DynamicSize {};
template<class T, class Size>
class Container;
template<class T>
class Container<T, DynamicSize>
{
public:
Container() {
std::puts("dynamic size");
}
};
template<class T, int Size>
class Container<T, Size>
{
public:
Container() {
std::puts("static size");
}
};
int main(int argc, char* argv[]) {
Container<char, 20> a;
Container<char, DynamicSize> b;
}
Eigen 库支持固定大小或运行时确定大小的矩阵,并执行与此类似的操作。那里的实现是模板参数始终是一个整型常量,动态标记只是一个等于 -1 的常量,但我很好奇是否还有其他方法。
我认为唯一的方法是让 Container
模板采用 Size
的类型参数。然后由类型负责处理它是动态的还是静态的。我认为任何特定于存储类型类型的细节都可以限制在 struct
类型中。也许下面的例子会有所帮助。
示例代码
#include <iostream>
struct DynamicSize
{
static const int size = -1;
};
template<int Size>
struct FixedSize
{
static const int size = Size;
};
template<class T, class Size>
class Container
{
public:
Container()
{
std::cout << Size::size << "\n";
}
};
int main()
{
Container<char, FixedSize<20>> a;
Container<char, DynamicSize> b;
return 0;
}
示例输出
20
-1
James 提出的解决方案非常好!
但是,如果确实需要部分专业化,正如问题最初的要求(例如,为了实现不同的行为在这两种不同的情况下),根据詹姆斯的回答,我建议:
#include <iostream>
struct DynamicSize {};
template<int Size>
struct FixedSize {};
template<class T, class Size>
class Container;
template<class T, int size>
class Container<T, FixedSize<size>> {
public:
Container() { std::cout << "FixedSize: " << size << "\n"; }
};
template<class T>
class Container<T, DynamicSize> {
public:
Container() { std::cout << "dynamic size\n"; }
};
// you can also do that
template<class T>
class Container<T, FixedSize<0>> {
public:
Container() { std::cout << "Special case of FixedSize 0\n"; }
};
int main() {
Container<char, FixedSize<20>> a;
Container<char, DynamicSize> b;
Container<char, FixedSize<0>> c;
}
示例输出
FixedSize: 20
dynamic size
Special case of FixedSize 0
但为什么要到此为止呢?
如果需要专注于大小本身(即为不同的固定大小值创建不同的实现,通过预定义范围选择),一个可以做到:
enum class SIZE_RANGE {SMALL, MEDIUM = 10, BIG = 100};
constexpr bool operator<(int size, SIZE_RANGE s) {
return size < (int)s;
}
//------------------------------------------------------------------------------------
// FixedSize manages its own range selection here
template<int Size,
SIZE_RANGE SizeRange = (Size < SIZE_RANGE::MEDIUM? SIZE_RANGE::SMALL :
Size < SIZE_RANGE::BIG? SIZE_RANGE::MEDIUM :
SIZE_RANGE::BIG)>
struct FixedSize {};
//------------------------------------------------------------------------------------
现在我们可以根据其范围专门研究 Container 的大小:
template<class T, class Size>
class Container;
template<class T>
class Container<T, FixedSize<0>> {
public:
Container() { std::cout << "Special case of FixedSize 0\n"; }
};
template<class T, int size>
class Container<T, FixedSize<size, SIZE_RANGE::SMALL>> {
public:
Container() { std::cout << "Small FixedSize: " << size << "\n"; }
};
template<class T, int size>
class Container<T, FixedSize<size, SIZE_RANGE::MEDIUM>> {
public:
Container() { std::cout << "Medium FixedSize: " << size << "\n"; }
};
template<class T, int size>
class Container<T, FixedSize<size, SIZE_RANGE::BIG>> {
public:
Container() { std::cout << "Big FixedSize: " << size << "\n"; }
};
template<class T>
class Container<T, DynamicSize> {
public:
Container() { std::cout << "dynamic size\n"; }
};
主要可以通过以下方式进行演示:
int main() {
Container<char, DynamicSize> a;
Container<char, FixedSize<0>> b;
Container<char, FixedSize<5>> c;
Container<char, FixedSize<42>> d;
Container<char, FixedSize<100>> e;
}
示例输出
dynamic size
Special case of FixedSize 0
Small FixedSize: 5
Medium FixedSize: 42
Big FixedSize: 100