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

时间:2011-03-14 16:51:57

标签: c++ templates

假设我有一个模板(称为ExampleTemplate),它带有两个参数:容器类型(例如list,vector)和包含类型(例如float,bool等)。由于容器实际上是模板,因此该模板具有模板参数。这是我必须写的:

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

你可能会问什么是“分配器”的事情。好吧,最初,我尝试了显而易见的事情......

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

...但我遗憾地发现了分配器的默认参数......

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

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

BAD

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

5 个答案:

答案 0 :(得分:14)

也许你更喜欢这个:

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

这使用“静态duck typing”。它也更灵活,因为它不会强制Container类型支持STL的Allocator概念。


也许使用type traits成语会给你一个出路:

#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 traits类。

答案 1 :(得分:5)

我建议创建适配器。

您的课程应使用课程要求的确切个性化级别创建:

template <template <class> C, template T>
class Example
{
  typedef T Type;
  typedef C<T> Container;
};

编辑:尝试提供更多内容很好,但注定要失败,请查看各种扩展:

  • std::vector<T>std::vector<T, std::allocator<T>>
  • std::stack<T>std::stack<T, std::deque<T>>
  • std::set<T>std::set<T, std::less<T>, std::allocator<T>>

第二个是适配器,所以不带分配器,第三个没有相同的arity。因此,您需要将责任放在用户身上。

如果用户希望使用不符合表达方式的类型,那么最简单的方法是提供(本地)适配器:

template <typename T>
using Vector = std::vector<T>; // C++0x

Example<Vector, bool> example;

我想知道在这里使用参数包(可变参数模板)......我不知道将C声明为template <class...> C是否可以解决问题,或者编译器是否需要可变参数上课。

答案 2 :(得分:3)

如果您希望能够以通常的方式使用模板模板参数,则必须提供完整的模板签名,包括默认参数。

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

如果要处理来自STL的容器的其他容器,可以将容器构造委托给帮助程序。

// Other specialization failed. Instantiate a std::vector.
template <typename T, typename C>
struct make_container_
{
    typedef std::vector<T> result;
};

// STL containers
template <typename T, template <class U, class V = allocator<U> > class C>
struct make_container_<T,C>
{
    typedef C<T> result;
};

// Other specializations
...

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

答案 3 :(得分:1)

我认为,需要重现所有模板参数,即使是默认值。请注意,标准本身不使用模板模板参数用于容器适配器,并且更喜欢使用常规模板参数:

template < class T , class Container = deque <T > > class queue { ... };
template < class T , class Container = vector <T>, class Compare = less < typename Container :: value_type > > class priority_queue { ... };

答案 4 :(得分:0)

以下代码将允许您执行类似于您要求的操作。当然,这不适用于标准容器,因为它必须已经是传递给模板的模板类的一部分。


/* Allows you to create template classes that allow users to specify only some
 * of the default parameters, and some not.
 *
 * Example:
 *  template <typename A = use_default, typename B = use_default>
 *  class foo
 *  {
 *              typedef use_default_param<A, int> a_type;
 *              typedef use_default_param<B, double> b_type;
 *              ...
 *  };
 *
 *  foo<use_default, bool> x;
 *  foo<char, use_default> y;
 */

struct use_default;

template<class param, class default_type>
struct default_param
{
        typedef param type;
};

template<class default_type>
struct default_param<use_default, default_type>
{
        typedef default_type type;
};

但我真的不认为这就是你要找的东西。您对容器执行的操作不太可能适用于任意容器,因为许多容器会遇到多个默认参数的问题,默认类型为非明显类型。