模板模板参数与推导的模板参数不一致

时间:2017-08-17 02:39:34

标签: c++ c++11 templates

以下代码无法使用错误template template argument has different template parameters than its corresponding template template parameter进行编译:

#include <tuple>
#include <vector>
#include <string>
#include <iostream>

template<template<typename, typename> class Blah, typename KeyType, typename ValueType>
void print_tuploid(const Blah<KeyType, ValueType>& tup) {
    std::cout << "first value: " << std::get<0>(tup) << " second value: " << std::get<1>(tup) << std::endl;
}

int main() {
  auto stuff = std::make_tuple(1, 2);
  print_tuploid(stuff);
}

此代码背后的初衷是无关紧要的,此时我只是想了解为什么这被认为无效。

如果我将对std::make_tuple的调用更改为std::make_pair,则代码会正确编译并运行,这会让我相信有一些特定于std::tuple的奇怪内容。

我原本以为std::tuple可能有一些我不知道的额外的,默认的模板参数,因为如果我将print_tuploid的定义更改为以下内容,则代码将编译为std::make_tuplestd::make_pair

template<template<typename...> class Blah, typename KeyType, typename ValueType>
void print_tuploid(const Blah<KeyType, ValueType>& tup) {
    std::cout << "first value: " << std::get<0>(tup) << " second value: " << std::get<1>(tup) << std::endl;
}

但是当我尝试使用以下代码转储推导出的stuff类型时:

#include <tuple>

template<typename T>
class TypePrinter;

int main() {
  auto stuff = std::make_tuple(1, 2);
  TypePrinter<decltype(stuff)> error;
}

它报告:implicit instantiation of undefined template 'TypePrinter<std::__1::tuple<int, int> >',让我相信情况并非如此。

另外,作为一个附带问题,为什么在这种情况下不会出现参考崩溃?以下代码也被视为无效:

#include <iostream>

template<template<typename, typename> class Blah, typename KeyType, typename ValueType>
void print_tuploid(Blah<KeyType, ValueType>&& tup) {
    std::cout << "first value: " << std::get<0>(tup) << " second value: " << std::get<1>(tup) << std::endl;
}

int main() {
  auto stuff = std::make_pair(1, 2);
  print_tuploid(stuff);
}

给出错误:no known conversion from 'std::__1::pair<int, int>' to 'pair<int, int> &&' for 1st argument

基本上我只是想通过了解这里究竟发生了什么来扩展我的模板知识。对于长篇文章感到抱歉,并提前感谢任何人能够提供的任何指导。

1 个答案:

答案 0 :(得分:5)

该函数的问题在于它与一个只需要2个参数的模板类匹配。实际上,std::tuple的模板签名为template <typename...>。区别在于tuple采用任意数量的模板参数,而您的函数需要2。

std::pair工作正常,因为模板签名是template <typename, typename>,它完全匹配。

虽然我无法找到最新版本,但有一项提案可以实现这种专业化。它似乎已经传入C ++ 17,或者至少与它类似,因为模板模板参数的cppreference页面认为这是一个有效的例子。我找到的提案是here

您的第二个版本不接受std::pair的原因是因为它需要一个右值引用。拥有(部分)专用类型后,您无法将&&视为转发参考。