为什么此模板推断失败

时间:2014-11-10 11:26:40

标签: 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);
}

我收到此错误

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.

要修复它,我需要像这样更改bar()的调用:

template<typename T>
void bar(const std::forward_list<T>& list) {
    auto item = getItem<T>(list.cbegin());
}

我不明白为什么编译器无法推断模板参数,奇怪的是编译器对foo()非常满意。

1 个答案:

答案 0 :(得分:8)

您试图从非推断的上下文中推断出模板参数,§[temp.deduct.type] / 5

  

未推断的上下文是:

     

- 使用qualified-id。

指定的类型的嵌套名称说明符

即。

template<typename T>
T getItem(typename std::forward_list<T>::const_iterator it)
                   ^^^^^^^^^^^^^^^^^^^^

§[temp.deduct.type] / 4

  

但是,在某些上下文中,该值不参与类型推导,而是使用模板参数的值,这些参数可以在别处推导或显式指定。 如果模板参数仅在非推断的上下文中使用且未明确指定,则模板参数推断将失败。

如果您尝试实例化foo it will give the same error。使用上面的代码,您没有收到foo的错误,因为依赖名称只是在实例化时查找(这通常称为两阶段查找)。 (CFR)。 Semantic correctness of non-instantiated C++ template functions