gar*_*ph0 2 c++ templates c++11 argument-deduction
这段代码不能用clang ++ 6.0或g ++ 4.9.1编译(代码没有意义,但这是实现它的最小例子):
#include <forward_list>
template<typename T>
T getItem(typename std::forward_list<T>::const_iterator it) {
return *it;
}
template<typename T>
void foo() {
std::forward_list<T> list;
auto item = getItem(list.cbegin());
}
template<typename T>
void bar(const std::forward_list<T>& list) {
auto item = getItem(list.cbegin());
}
int main() {
std::forward_list<int> list;
bar(list);
}
Run Code Online (Sandbox Code Playgroud)
我收到这个错误
t2.cpp:17:17: error: no matching function for call to 'getItem'
auto item = getItem(list.cbegin());
^~~~~~~
t2.cpp:22:5: note: in instantiation of function template specialization 'bar<int>' requested here
bar(list);
^
t2.cpp:4:3: note: candidate template ignored: couldn't infer template argument 'T'
T getItem(typename std::forward_list<T>::const_iterator it) {
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,我需要改变这样bar()的呼叫:
template<typename T>
void bar(const std::forward_list<T>& list) {
auto item = getItem<T>(list.cbegin());
}
Run Code Online (Sandbox Code Playgroud)
我不明白为什么编译器无法推断模板参数,奇怪的是编译器非常满意foo().
您试图从非推导的上下文中推导出模板参数,§[temp.deduct.type]/5
未推断的上下文是:
- 使用qualified-id指定的类型的嵌套名称说明符.
即
template<typename T>
T getItem(typename std::forward_list<T>::const_iterator it)
^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
和§[temp.deduct.type]/4
但是,在某些上下文中,该值不参与类型推导,而是使用模板参数的值,这些参数可以在别处推导或明确指定.如果模板参数仅在非推导的上下文中使用且未明确指定,则模板参数推断将失败.
如果您尝试实例化foo 它将给出相同的错误.您没有因foo上面的代码而获得错误,因为依赖名称只是在实例化时查找(这通常称为两阶段查找).(CFR).非实例化C++模板函数的语义正确性