积分常量与 A 类型的部分特化

Partial Specialization for an Integral Constant vs a Type

本文关键字:常量 类型      更新时间:2023-10-16
是否可以

根据模板参数是类型还是整数常量来专门化模板?下面是一个不编译但说明了意图的示例:

#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;
}

特征库支持固定大小或运行时确定大小的矩阵,并执行与此类似的操作。那里的实现是模板参数始终是一个整数常量,动态标签只是一个等于 -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

现场示例

詹姆斯提出的解决方案非常好!

但是,如果确实需要部分专业化,正如问题中最初要求的那样(例如,在两种不同情况下实现不同的行为),则根据詹姆斯的回答,我会建议:

#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 sizen"; }
};
// you can also do that    
template<class T>
class Container<T, FixedSize<0>> {
public:
    Container() { std::cout << "Special case of FixedSize 0n"; }
};
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 {};
//------------------------------------------------------------------------------------

现在我们可以根据容器的范围专门研究容器的大小:

template<class T, class Size>
class Container;
template<class T>
class Container<T, FixedSize<0>> {
public:
    Container() { std::cout << "Special case of FixedSize 0n"; }
};
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 sizen"; }
};

这可以通过以下主要来证明:

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

现场示例