我有一个带有两个模板参数的模板(MyCollection)和另一个模板(TCTools),期望一个模板带有一个模板参数作为模板参数。
我定义了一个"桥接" (TypedCollection)获取一个带有MyCollection中一个参数的模板,以及一个参数,它的第一个参数是为了将它传递给模板模板。
这很好,如果我使用固定类型的桥作为参数,但是使用另一个模板的参数从另一个模板调用它将无法编译。
#include <iostream>
using std::size_t;
template <class Scalar, size_t size>
struct MyCollection
{
MyCollection()
{
std::cout << "Made collection"
<< std::endl
<< " " << __PRETTY_FUNCTION__
<< std::endl;
}
};
template <class Scalar>
struct TypedCollection
{
template <size_t size>
using value = MyCollection<Scalar, size>;
};
template <template <size_t> class TC>
struct TCTools
{
static TC<10> *make_10_sized()
{
return new TC<10>();
}
};
template <class S>
void test()
{
// Will not compile
TCTools<TypedCollection<S>::value>::make_10_sized();
}
int main()
{
// works
TCTools<TypedCollection<int>::value>::make_10_sized();
test<int>();
return 0;
}
海湾合作委员会提供以下说明:
expected a class template, got ‘TypedCollection<S>::value’
整件事让我很困惑。为什么test()中的调用没有编译,而main()中的调用正如预期的那样工作?是否有可能让测试工作?
答案 0 :(得分:3)
TCTools<TypedCollection<S>::template value>::make_10_sized()
很像typename
(但容易混淆),你必须消除value
的歧义,或者编译器假定它是值而不是类型或模板。
在替换S
之前执行此操作。从理论上讲,TypedCollection<S>
的特化可以使value
任意一点,并且编译器不会尝试猜测。
顺便说一句,如果你最终做了更多的元编程,你会发现模板,非类型和类型模板参数真的很痛苦。
一种方法是将所有3种变成类型。
template<template<class...>class Z>
struct ztemplate_t {
template<class...Ts> using apply=Z<Ts...>;
};
// C++17
template<auto x>
using zvalue_t = std::integral_constant< std::decay_t<decltype(x)>, x >;
// C++11
template<std::size_t x>
using zsize_t = std::integral_constant< std::size_t, x >;
然后我们可以编写像apply
这样的模板,将ztemplate
作为第一个参数并将其应用于其余参数,然后zapply
即ztemplate<apply>
。
完成繁重的工作后,TypedCollection<T>
变为partial_apply_t< zMyCollection_t, T>
。
另一种方法是将所有3个变为constexpr值并进行constexpr值式元编程。
在此之下,我们最终得到type_t< decltype(zpartial_apply( zMyCollection, tag<T> ))>
。
但是对于小型的一次性图书馆来说,这两个都是过度的。