内部模板类型std::vector<std::vector<T>>的函数模板重载或特化

3
如何实现针对内部模板类型std :: vector >的函数模板重载。
我有一个重载了模板的程序和一个具有映射、对和向量的复杂数据结构。
#include <iostream>
#include <vector>
#include <map>
#include <utility>
#include <typeinfo>

template<typename Test, template<typename...> class Ref> //#6
struct is_specialization : std::false_type {};

template<template<typename...> class Ref, typename... Args> //#7
struct is_specialization<Ref<Args...>, Ref>: std::true_type {};
template <typename T>
bool f(T& x) // #1
{
    std::cout << "body of f\n";
    return f(x);
}

template <typename T>
bool f(std::vector<T>& v) // #2
{
    std::cout << "body of f for vectors\n";
    return true;
}
template<typename T>
typename std::enable_if<is_specialization<typename T::value, std::vector>::value, T>::type
    bool f(std::vector<T>& v) // #5
    {
        std::cout << "body of f for vectors<vectors>\n";
        return true;
    }

template <typename Key, typename Value>
bool f(const std::pair<Key,Value>& v) // #3
{
    std::cout << "body of f for pairs\n";
    for(auto& e: v) {
      f(e.first);
    }
    for(auto& e: v) {
      f(e.second);
    }
    return true;
}

template <typename Key, typename Value>
bool f(std::map<Key,Value>& v) // #4
{
    std::cout << "body of f for maps\n";
    for(auto& e: v) {
      f(e.first);  // expecting this call goes to #3
    }
    for(auto& e: v) {
      f(e.second);
    }
    return true;
}

int main() {
  std::vector<int> v{1,2};
  std::map<std::pair<int,int>,std::vector<std::vector<int>>> m_map = {
                                            {{10,20}, {{5,6},{5,6,7}}},
                                            {{11,22}, {{7,8},{7,8,9}}}
                                        };
    f(m_map); // this call goes to #4
} 

每次都会调用 #2 来处理向量,但对于 std::vectors<std::vector<T>>,我需要调用 #5 并且还会出现编译错误,关于 std::enable_if 中使用的 ::type 有问题。

请告诉我这个程序有什么问题以及如何使其正常工作。

另外,有人能解释一下关于模板参数包中 #6 和 #7 的意义吗?它是如何工作的呢?

谢谢。


2
你尝试过为std::vector<std::vector<T>>编写重载函数吗?(你的第6/7个问题应该是一个单独的问题。) - Davis Herring
@Davis 是的,我试过了,但不起作用,是的,#6和#7我可以将其作为一个单独的问题。 - TechTotie
1个回答

4
我认为编写f()std::vector<std::vector<T>>特化的最简单方式如下:
template<typename T>
bool f (std::vector<std::vector<T>>& v) // #5
 {
   std::cout << "body of f for vectors<vectors>\n";
   return true;
 }

这样您就可以重载模板函数f(),使其比#2更加专业。
如果您想使用SFINAE和您的is_specialization,我认为正确的方法如下。
template <typename T>
typename std::enable_if<is_specialization<T, std::vector>::value, bool>::type
f (std::vector<T> & v) // #5
 {
   std::cout << "body of f for vectors<vectors>\n";
   return true;
 }

很不幸,这个版本是专门为版本 #2 设计的,当您使用 std::vector<std::vector<T>> 参数调用 f() 时,会出现歧义导致编译错误。

要解决这个问题,您需要禁用 #2 版本。

template <typename T>
typename std::enable_if<! is_specialization<T, std::vector>::value, bool>::type
f (std::vector<T> & v) // #2
 {
   std::cout << "body of f for vectors\n";
   return true;
 }

在您的原始版本中,您使用typename T :: type ...但是当 T 不是定义了 type 的类时,会出现错误。
另外,您返回两种类型。
template<typename T>
typename std::enable_if<is_specialization<typename T::value,
                        std::vector>::value, T>::type // <<--- type 1: T
    bool f(std::vector<T>& v) // #5
//  ^^^^  type2: bool

使用SFINAE的方式,返回类型必须用std::enable_if表达。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接