【发布时间】:2013-10-15 20:16:33
【问题描述】:
考虑以下代码,它使用“模板模板”参数来实例化一个使用多种类型的类模板:
#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,因为模板模板参数只声明了一个参数(一个 Enum),但 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 只提供了一个模板参数。显然,我无法在此处隐式使用默认参数。
有什么方法可以在模板模板函数中使用模板的默认参数吗?
【问题讨论】:
-
在您对
do_someting的最终定义中,您能否将第一个class替换为class=void?这可能会告诉它Action是一个带有一个默认值的双参数模板。我想我不希望它起作用,因为这意味着默认值被指定了两次! -
这确实有效。这是标准允许的吗?
-
这是我的一个疯狂猜测!不知道标准。我在 g++-4.6.3 上,它对我有用。
-
@AaronMcDaid [temp.param]/14 "模板 template-parameter 的 template-parameter 允许有一个默认 模板参数。”但是,这不会影响模板是否是有效的模板模板参数(它并不是很有用,live example)。
-
在我的实验中,在 g++-4.6.3 上,
do_something中指定的任何默认值都优先于Foo中指定的任何默认值。这有点奇怪,即使它是标准的,我也不喜欢它。有没有一种更简洁的方法来制作单参数模板,它是双参数默认模板的别名。 AFAIK,C++11 中的新using模板别名可能是相关的。