C++函数的嵌套模板参数

35
我希望在C++中拥有一个模板函数,其中一个模板参数本身是另一个模板参数的模板。如果这没有任何意义,请看下面的代码,它打印了一个以类型T为模板的std::vector。
template <typename T>
void print_vector(std::vector<T> &vec)
{
    for(auto v: vec)
        std::cout << v << " ";
    std::cout << std::endl;
}
...
std::vector<double> vec(5);
...
print_vector(vec);

我希望进一步将这个函数推广到除了vector之外的STL容器。但是我不知道如何“嵌套”模板参数,使容器在类型T上进行模板化。我尝试过以下方法,但没有成功。

template <typename T, template <typename TT> V>
void print_container(V<T> &con)
{
    for(auto c: con)
        std::cout << c << " ";
    std::cout << std::endl;
}
...
std::vector<double> vec(5);
...
print_container(vec);

我确定这个问题之前已经在这里回答过,但我找不到搜索术语来找到答案。
感谢 @ForEveR。你的回答非常准确!对于我提出的问题,所有回答都指出不需要将“存储”类型 T 模板化,以下解决方案足以满足我的需求:
template <typename C>
void print_container(C &con)
{
    for(auto v: con)
        std::cout << v << " ";
    std::cout << std::endl;
}

很不幸,激发这个问题的实际用例有一些更加复杂。这个程序需要多个容器,例如线性代数示例中的矩阵和向量类:

template <typename MATRIX, typename VECTOR>
void mat_vec_multiply(const MATRIX &A, const VECTOR &x, VECTOR &y)
{
    // Implement y = A*x;
}

假设MATRIX和VECTOR类必须基于相同的底层存储类进行模板化(即double、float、int等)。这样,通过明确指定T作为模板参数,我们可以强制执行此操作。
template < typename T,
           template<typename> class MATRIX,
           template<typename> class VECTOR>
void mat_vec_multiply(const MATRIX<T> &A, const VECTOR<T> &x, VECTOR<T> &y)
{
    // Implement y = A*x;
}

很遗憾,我正在使用CUDA编译器 nvcc,它不支持C++11结构(我在示例中使用C++11只是因为它更简洁)。所以我不能使用std :: is_samestatic_assert,尽管我想我可以轻松地自己编写is_same(或使用Boost)。在这种情况下,我想强制执行存储类的公共模板参数,什么是最佳实践?
3个回答

34

std::vector有两个参数,类型和分配器。 尝试一下:

template <typename T, typename Alloc, template <typename, typename> class V>
void print_container(V<T, Alloc> &con)
{
}

print_container(vec);

这适用于vector、list等,但不适用于map、set。
然而,由于您使用的是auto,您可以使用C++11,然后您可以这样做:
template <typename T, template <typename, typename...> class V, typename... Args>
void print_container(V<T, Args...> &con)

或者

template <template <typename, typename...> class V, typename... Args>
void print_container(V<Args...> &con)

当然,最简单的方法就是像这样做:
template<typename C>
void print_container(C& con)

很可能需要一些检查来推断,C 真的是容器。

template<typename C>
auto print_container(C& con) -> decltype(con.begin(), void())

7
你最好完全不要这样做;考虑只在容器上进行模板化。
template <typename C>
void print_container(const C& container)
{

    for(auto v: container)
        std::cout << v << " ";
    std::cout << std::endl;
}

如果您需要在函数中使用存储的类型,您可以使用: `typedef typename C::value_type T;`

3

我不确定我理解你想要什么,但你可以尝试以下方法:

template <typename V>
void print_vector(V &vec)
{
    for(auto v: vec)
        std::cout << v << " ";
    std::cout << std::endl;
}
...
std::vector<double> vec(5);
...
print_vector(vec);

这里的重点是通常不需要像 template < template V< typename T> > 这样的构造,因为整个模板 template V< typename T> 可以泛化为类型 V

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接