2017-06-20 89 views
2

我有类似下面一个很简单的测试程序:C++:为什么模板不能用于推导容器和元素类型?

#include<vector> 
#include<iostream> 
using namespace std; 
template<typename C, typename E> 
void f(const C<E>& container){ 
    cout<<container.size()<<endl; 
} 
int main(){ 
    vector<int> i; 
    f(i); 
    return 0; 
} 

它无法用gcc 4.1.2编译。错误信息:

templateContainer.cpp:5: error: ‘C’ is not a template 
templateContainer.cpp: In function ‘int main()’: 
templateContainer.cpp:10: error: no matching function for call to ‘f(std::vector<int, std::allocator<int> >&)’ 
+1

这就是为什么容器有*关联类型*。你不需要'E';只需编写'typename C :: value_type'(或者'typename C :: reference_type')。 –

+0

为了澄清,错误信息是因为'C'被**定义**为一个类型的名字('typename C'),但它被**用作**模板的名字('C ') 。它不能兼而有之。 –

回答

9

你可以使用一个模板的模板参数(请注意,std::vector其实需要一个以上的模板参数族的元素类型和分配器类型]):

template<template <typename...> class C, typename... E> 
void f(const C<E...>& container){ 
    cout<<container.size()<<endl; 
} 

Live Demo


如果您不需要类型分解,你可以简单地使用一个O rdinary模板。

template<typename C> 
void f(const C& container){ 
    cout<<container.size()<<endl; 
} 

你还可以从STL容器获得的typedef:例如,如果你想知道类型由容器保存元素value_type是有你。

template<typename C> 
void f(const C& container){ 
    using ValueType = typename C::value_type; 
    cout<<container.size()<<endl; 
} 
+0

没有可变参数模板(即C++ 11),需要事先知道参数的数量? – user463035818

+0

@ tobi303,是的,否则,一些旧的令人不愉快的重载许多模板参数的技巧 – WhiZTiM

+2

请注意,虽然这是绝对正确的答案,如上所述的问题,如果你真的用它来推断容器的值类型,你应该得到当场被解雇。容器具有关联类型的typedef,你应该总是使用这些。因为容器契约需要这些,并且不*要求值类型完全成为模板参数。 –

1

std :: vector有两个模板参数,type和allocator。

template <template<class, class> class C, class E, class A> 
void f(const C<E, A> &container) 
{ 
    std::cout << container.size() << endl; 
} 

int main() 
{ 
    std::vector<int> i; 
    f(i); 
    return 0; 
} 
1

虽然WhiZTiM的答案是正确的(当然,更喜欢第二部分),它没有解释为什么代码不起作用。

假设为您打算大致

template<template <typename> class C, typename E> void f(const C<E>&); 

std::vector不匹配的原因,那一刻是,它是错误的外形 - 它有两个类型参数,而不是一个在你的声明。

仅仅因为你不经常明确写入默认的第二个(分配器)参数,并不意味着它不存在。

为了比较,这个工作(或没有)以类似的方式:

void f(int); 
void g(int, int* = nullptr); 

void apply(void (*func)(int), int); 

apply(f, 42); // ok - f matches shape void(*)(int) 
apply(g, 42); // error - g is really void(*)(int,int*) 

具体而言,默认参数(或参数类型)是语法糖。它们允许您在调用(实例化)站点处忘记这些参数,但不要更改函数(或模板)的形状。

相关问题