是否可以在可变参数模板中推断出容器类型

Can the container type be deduced in variadic templates?

本文关键字:推断出 类型 变参 参数 是否      更新时间:2023-10-16

In C++11/C++14,

template <
   typename T ,
   template <typename...> class Container_t
>
void MyFunc(Container_t<T> &data) { ... }

template <typename T>
void MyFunc2( T v ) { ... }

int main()
{
   std::vector<char> v;
   MyFunc<char, std::vector>(v);     // OK
   MyFunc(v);                        // error
   int i;
   MyFunc2<int>(i);                  // OK
   MyFunc2(i);                       // OK
}

我收到MyFunc(v)错误.

是否有可能以任何方式让编译器找出传递给可变参数模板函数的容器的类型?我认为找出它没有问题,就像普通模板中的普通类型一样。

如果我需要更改 v 的类型,我是否必须修复对 MyFunc 的所有调用?

编译器:Microsoft Visual C++ 2015 (v140)

与其尝试推断容器类型,不如假设容器定义了它存储的类型。

template <typename Container>
void MyFunc(Container& data)
{ 
   // all std containers defines value_type member (also reference etc.)
   using std::begin;
   using value_type = typename Container::value_type;
   value_type value = *begin(data);
  ...
}

请注意,您可能根本不需要存储元素的类型:

template <typename Container>
void MyFunc(Container& data)
{ 
   using std::begin;
   auto value = *begin(data);
  ...
}

如果您只想处理 std 容器(或具有类似模板参数的容器) - 请参阅 Richard Hodges 的答案。

诀窍是命名模板的模板参数:

#include <vector>
#include <iostream>
#include <typeinfo>
template <
   typename T ,
   typename A,
   template <typename = T, typename = A> class Container_t
>
void MyFunc(Container_t<T, A> &data) { 
     std::cout << "value type = " << typeid(T).name() << std::endl;
     std::cout << "allocator type = " << typeid(A).name() << std::endl;
     std::cout << "container type = " << typeid(Container_t<T,A>).name() << std::endl;
   }

template <typename T>
void MyFunc2( T v ) {  }

int main()
{
   std::vector<char> v;
   MyFunc<char, std::allocator<char>, std::vector>(v);     // OK
   MyFunc(v);                        // now ok
}

如果您不关心除值类型和容器之外的任何东西......

#include <vector>
#include <map>
#include <iostream>
#include <typeinfo>
template <
   typename T ,
   typename...Rest,
   template <typename, typename...> class Container_t
>
void MyFunc(Container_t<T, Rest...> &data) { 
     std::cout << "value type = " << typeid(T).name() << std::endl;
     std::cout << "container type = " << typeid(Container_t<T,Rest...>).name() << std::endl;
   }

template <typename T>
void MyFunc2( T v ) {  }

int main()
{
   std::vector<char> v;
   std::map<char, int> m;
//   MyFunc<char, std::allocator<char>, std::vector>(v);     // OK
   MyFunc(v);                        // now ok
   MyFunc(m);                        // now ok
}

我的猜测是这是一个VC ++错误,因为GCC和CLANG可以推断出输入模板参数。正如KerrekSB在评论中提出的那样,一个不那么痛苦的解决方法如下:

template<typename T, template<typename...> class Container_t, typename... Args>
void MyFunc(Container_t<T, Args...> &data) { 
  ...
}

现场演示