模板模板参数和默认参数

时间:2013-10-15 20:16:33

标签: c++ templates

考虑以下代码,该代码使用“模板模板”参数来使用多种类型实例化类模板:

#include <iostream>
using namespace std;

enum E
{
    a = 0,
    b = 1
};

template <template <E> class Action, class T>
void do_something(const T& value)
{
    typedef Action<a> type1;
    typedef Action<b> type2;
}

template <E e, class Enable = void>
class Foo
{

};

int main()
{
    do_something<Foo>(int(55));
}

使用较旧的编译器(GCC 4.1.2),上面的代码编译得很好。但是,使用较新的编译器(GCC 4.4.6或4.8.1)会产生以下错误:

test3.cpp:25:27: error: no matching function for call to ‘do_something(int)’
  do_something<Foo>(int(55));

所以看起来GCC无法绑定到do_something,因为模板模板参数只声明一个参数(一个枚举),但Foo实际上需要两个模板参数(即使一个是默认。)我猜GCC 4.1.2允许忽略默认参数。

好的,如果我将模板定义更改为:

template <template <E, class> class Action, class T>
void do_something(const T& value)
{
    typedef Action<a> type1;
    typedef Action<b> type2;
}

...然后我测试的GCC版本都没有编译它。它们都会产生类似的错误:

test3.cpp:13: error: wrong number of template arguments (1, should be 2)
test3.cpp:10: error: provided for ‘template<E <anonymous>, class> class Action’

现在,编译器抱怨,因为表达式typedef Action<a> type1仅提供单个模板参数。显然,我无法隐式使用默认参数。

我是否可以通过某种方式在模板模板函数中使用模板的默认参数?

2 个答案:

答案 0 :(得分:6)

模板参数的参数将忽略默认参数。 n3337中有这个例子,章节[temp.arg.template],第2段:

template<class T> class A { /∗ ... ∗/ };
template<class T, class U = T> class B { /∗ ... ∗/ };
template <class ... Types> class C { /∗ ... ∗/ };
template<template<class> class P> class X { /∗ ... ∗/ };
template<template<class ...> class Q> class Y { /∗ ... ∗/ };
X<A> xa; // OK
X<B> xb; // ill-formed: default arguments for the parameters of a template argument are ignored
X<C> xc; // ill-formed: a template parameter pack does not match a template parameter
Y<A> ya; // OK
Y<B> yb; // OK
Y<C> yc; // OK

请注意上面X<B> xb;处的评论。我不敢找到规范性文本。

您可以将其与函数相关联 - 默认参数也不是签名的一部分。如果您尝试通过函数指针调用具有参数默认值的函数,也会发生同样的事情。

答案 1 :(得分:1)

使用using模板别名(C ++ 11中的新功能),您可以创建一个单参数模板,该模板等同于另一个具有两个参数的模板,其中一个参数是默认的。

template <E e> using Foo1 = Foo<e>;

这创建了Foo1,一个单参数模板,即使Foo在技术上有两个参数,其中一个是默认的。您可以将其用作:

do_something<Foo1>(int(55));

或者,如果using等C ++ 11功能不可用,则扫描会在您的do_something声明中指定默认值。不幸的是,这意味着do_something无法再处理简单的单工具模板。因此,我认为上面的using方法更好。

template <template <E, class = void> class Action, class T>
void do_something(const T& value);

如果采用这种方法,将args中的默认值设置为do_something,则此默认值优先于声明Foo中指定的默认值。这是基于我的实验,我不能自信地评论标准是什么,不是标准。但我确实认为using技巧完全符合C ++ 11标准。

(Ubuntu clang version 3.0-6ubuntu3)