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

时间:2017-10-31 15:23:11

标签: c++ c++11 templates template-templates

我有一个带有两个模板参数的模板(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()中的调用正如预期的那样工作?是否有可能让测试工作?

1 个答案:

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

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

另一种方法是将所有3个变为constexpr值并进行constexpr值式元编程。

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

但是对于小型的一次性图书馆来说,这两个都是过度的。