积分常数与类型的部分特化

时间:2016-06-01 22:51:15

标签: c++ templates partial-specialization

是否可以根据模板参数是类型还是整数常量来专门化模板?这是一个没有编译但是说明意图的例子:

#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的常量,但我很好奇,如果有另一种方式。

2 个答案:

答案 0 :(得分: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

Live Example

答案 1 :(得分:0)

詹姆斯建议的解决方案非常好!

但是,如果确实需要 部分特化 ,最初在问题中请求(例如,在两种不同的情况下实现不同的行为),骑马关于詹姆斯回答,我建议:

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

现在我们可以专注于容器的大小,根据其范围:

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

Live Example