带有模板参数的模板中的默认值 (C++)

2021-12-13 00:00:00 templates c++

假设我有一个模板(称为 ExampleTemplate),它接受两个参数:容器类型(例如列表、向量)和包含类型(例如 float、bool 等).由于容器实际上是模板,因此该模板具有模板参数.这是我必须写的:

Assume I have a template (called ExampleTemplate) that takes two arguments: a container type (e.g. list, vector) and a contained type (e.g. float, bool, etc). Since containers are in fact templates, this template has a template param. This is what I had to write:

#include <vector>
#include <list>

using namespace std;

template < template <class,class> class C, typename T>
class ExampleTemplate {
    C<T,allocator<T> > items;
public:
    ....
};

main()
{
    ExampleTemplate<list,int> a;
    ExampleTemplate<vector,float> b;
}

您可能会问什么是分配器".嗯,最初,我尝试了显而易见的事情......

You may ask what is the "allocator" thing about. Well, Initially, I tried the obvious thing...

template < template <class> class C, typename T>
class ExampleTemplate {
    C<T> items;
};

...但不幸的是我发现分配器的默认参数...

...but I unfortunately found out that the default argument of the allocator...

   vector<T, Alloc>
   list<T, Alloc>
   etc

...必须在模板声明中明确保留".如您所见,这使代码变得更丑陋,并迫使我重现模板参数(在本例中为分配器)的默认值.

...had to be explicitely "reserved" in the template declaration. This, as you can see, makes the code uglier, and forces me to reproduce the default values of the template arguments (in this case, the allocator).

哪个是坏.

问题不是关于容器的具体问题――而是关于带有模板参数的模板中的默认值",上面只是一个例子.取决于 STL 容器具有::value_type"的知识的答案不是我所追求的.想想一般的问题:如果我需要在模板ExampleTemplate中使用模板参数C,那么在ExampleTemplate的主体中,我使用时是否必须重现C的默认参数?如果我不得不这样做,会不会引入不必要的重复和其他问题(在这种情况下,C 是 STL 容器,可移植性问题 - 例如分配器")?

The question is not about the specific problem of containers - it is about "Default values in templates with template arguments", and the above is just an example. Answers depending on the knowledge that STL containers have a "::value_type" are not what I am after. Think of the generic problem: if I need to use a template argument C in a template ExampleTemplate, then in the body of ExampleTemplate, do I have to reproduce the default arguments of C when I use it? If I have to, doesn't that introduce unnecessary repetition and other problems (in this case, where C is an STL container, portability issues - e.g. "allocator" )?

推荐答案

也许你更喜欢这个:

#include <vector>
#include <list>

using namespace std;

template <class Container>
class ForExamplePurposes {
    typedef typename Container::value_type T;
    Container items;
public:
};

int main()
{
    ForExamplePurposes< list<int> > a;
    ForExamplePurposes< vector<float> > b;
}

这使用静态鸭子打字".它也更加灵活,因为它不强制容器类型支持 STL 的分配器概念.

This uses "static duck typing". It is also a bit more flexible as it doesn't force the Container type to support STL's Allocator concept.

也许使用 type traits 习语可以给你一个出路:

Perhaps using the type traits idiom can give you a way out:

#include <vector>
#include <list>

using namespace std;

struct MyFunkyContainer
{
    typedef int funky_type;
    // ... rest of custom container declaration
};

// General case assumes STL-compatible container
template <class Container>
struct ValueTypeOf
{
    typedef typename Container::value_type type;
};

// Specialization for MyFunkyContainer
template <>
struct ValueTypeOf<MyFunkyContainer>
{
    typedef MyFunkyContainer::funky_type type;
};


template <class Container>
class ForExamplePurposes {
    typedef typename ValueTypeOf<Container>::type T;
    Container items;
public:
};

int main()
{
    ForExamplePurposes< list<int> > a;
    ForExamplePurposes< vector<float> > b;
    ForExamplePurposes< MyFunkyContainer > c;
}

想要将 ForExamplePurposes 与非 STL 兼容容器一起使用的人需要专门化 ValueTypeOf 特征类.

Someone who wants to use ForExamplePurposes with a non-STL-compliant container would need to specialize the ValueTypeOf traits class.

相关文章