部分填充的模板作为模板模板的参数

Partially filled template as parameter for template template

我有一个带有两个模板参数的模板 (MyCollection) 和另一个模板 (TCTools),需要一个带有一个模板参数的模板作为模板参数。

我定义了一个 "bridge" (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;
}

GCC 给出了以下注释:

expected a class template, got ‘TypedCollection<S>::value’

整个事情让我很困惑。为什么 test() 中的调用未编译,而 main() 中的调用按预期工作?是否可以让测试工作?

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 作为第一个参数并将其应用于其余参数,然后 zapplyztemplate<apply>.

完成繁重的工作后,TypedCollection<T> 变为 partial_apply_t< zMyCollection_t, T>


另一种是将所有 3 个都转换为 constexpr 值并进行 constexpr 值式元编程。

在此之下,我们最终得到 type_t< decltype(zpartial_apply( zMyCollection, tag<T> ))>


但是对于小型的一次性图书馆来说,这两种方法都太过分了。