5

我有以下代码:

template<class T, int I=44> struct test {T j = I;};

template<int J> struct test<int, J> {int j = J;};

int main()
{
  test<55> jj;

  std::cout << jj.j << std::endl;
  return(1);
}

编译器(clang)仅抱怨该行test<55> jj

我不明白为什么?有解决办法吗?

如果它抱怨那条线,为什么不抱怨第二个模板定义呢?

提前致谢。

消息是:

enable.cpp:17:8: error: template argument for template type parameter must be a type
test<55> jj;
   ^~
enable.cpp:9:16: note: template parameter is declared here
template<class T, int I=44> struct test
4

2 回答 2

6

问题是您还没有理解选择类模板专业化是如何工作的。

你的专业:

template<int J> struct test<int, J> {int j = J;};

不会创建您只需为其传递单个 int 模板参数的模板。

test<55> jj; // doesn't work because there's no template<int J> struct test

相反,它所做的是创建一个特化template<class T, int I> struct test,当模板参数匹配特化时将使用该template<class T, int I> struct test特化,即test<int,J>.

test<int,55> jj; // uses the specialization template<int J> struct test<int, J>

以下是标准中的关键引述:

在引用类模板特化的类型名称中(例如 A<int, int, 1>),实参列表应与主模板的模板形参列表匹配。特化的模板参数是从主模板的参数推导出来的。 [重点补充]

                                                                                   — 14.5.5.1 [temp.class.spec.match] p4


您似乎试图设置int为的默认类型,T同时为I. 我认为您的意图是能够指定一个类型和一个值,仅指定一个类型并将 44 作为默认值,或者仅指定一个值并将 int 作为默认类型。

不幸的是,我不知道如何指定这样的独立默认值。您可以指定默认值 ( template<class T=int, int I=44> struct test),但获取默认类型也需要接受默认值。

但是,如果您愿意使用第二个名称,那么您可以这样做:

template <int I>
using test_int = test<int, I>;

这将创建一个模板别名,因此您只需指定一个值:

test_int<55> jj;

这最终将使用test<int, I>发生的任何特化来解决是否存在显式特化或编译器生成隐式特化。

于 2012-07-23T16:09:50.530 回答
3

第一个错误发生是因为编译器试图用 55 实例化第一个模板参数 ( class T)。这不起作用,因为 55 本身不是类型,而是它的实例化。但是,test<int>因为这里的模板参数是模板签名所要求的类型,所以有效。

相反,您想要的是类型的“currying”,也就是。模板别名:

template <typename T>
struct test2 = using test<T, 55>;

在这里您只需要提供一个T 选择 55 作为固定的第二个参数。但是您仍然需要通过给它一个具体的 来使用该类型T,例如test2<double>.

评论表明您也可能对以下变体感兴趣:

template <int I>
using test3 = test<int, I>;

在这里,您将第一个类型参数固定为 int,这允许您像在代码中一样使用它:

test3<55> t;
于 2012-07-23T15:36:16.317 回答