上下文相关的模板参数推导 - 参数的类型/值不匹配

Posted

技术标签:

【中文标题】上下文相关的模板参数推导 - 参数的类型/值不匹配【英文标题】:Context depended template argument deduction - type/value mismatch at argument 【发布时间】:2020-09-17 14:12:35 【问题描述】:

小例子

#include <vector>
#include <tuple>

template<typename T>
void function(std::vector<T> vec)

    auto tup = std::tuple<decltype(vec)::iterator>(vec.begin());


int main(int argc, char* args[])

    std::vector<int> vec = 1,2,3;

    auto tup = std::tuple<decltype(vec)::iterator>(vec.begin());

    function(vec);
    return 0;

尝试编译给出

error: type/value mismatch at argument 1 in template parameter list for ‘template<class ... _Elements> class std::tuple’
auto tup = std::tuple<decltype(vec)::iterator>(vec.begin());
                                              ^
note:   expected a type, got ‘decltype (vec)::iterator’

here 描述的解决方案建议添加typename。将typename 放在function 中的decltype 前面可以解决编译问题。然而:

    为什么不能推断出类型? 根本问题是什么? (显然编译器怀疑 decltype(...)::iterator 是一种类型。但为什么它在main 中有效,而在function 中无效?)

【问题讨论】:

鉴于您已标记 C++17(因此 CTAD - 类模板参数推导 - 可用)并且 vec.begin() 的类型为 decltype(vec)::iterator,您可以简单地编写 auto tup = std::tuplevec.begin();。在 C++11/C++14 中,您可以改用 std::make_tuple(): auto tup = std::make_tuple(vec.begin()); 这条评论对我来说和答案本身一样有价值! 【参考方案1】:

由于iterator是一个依赖名称,所以需要使用typename关键字来消除歧义:

auto tup = std::tuple<typename decltype(vec)::iterator>(vec.begin());
                  //  ^^^^^^^^

请注意,vec 只是 function 中的一个从属名称。在main 内部它不是依赖的,所以你不需要说typename

【讨论】:

以上是关于上下文相关的模板参数推导 - 参数的类型/值不匹配的主要内容,如果未能解决你的问题,请参考以下文章

模板参数推导与 QT lambda 不匹配

深入理解函数模板

模板别名、变量模板和自动类型推导无法推导模板参数

ByRef 参数类型与布尔值不匹配

从std :: function中推导返回和参数类型作为模板函数参数传递?

参数和返回类型中的模板类型推导