可以在可变参数模板中推导出容器类型吗?

时间:2016-05-19 17:06:36

标签: c++ templates c++11 variadic-templates

在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)

3 个答案:

答案 0 :(得分:8)

假设容器定义它存储的类型,而不是尝试推断容器类型。

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 answer。

答案 1 :(得分:4)

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

#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

}

答案 2 :(得分:1)

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

writeErrorStream      : True
PSMessageDetails      : 
Exception             : System.Management.Automation.RuntimeException: A directory not found 
                        error occurred while registering scheduled job definition testing.  
                        Make sure you are running Windows PowerShell with elevated privileges. 
                        ---> Microsoft.PowerShell.ScheduledJob.ScheduledJobException: An error 
                        occurred while registering scheduled job definition testing to the 
                        Windows Task Scheduler.  The Task Scheduler error is: The system cannot 
                        find the path specified. (Exception from HRESULT: 0x80070003). ---> 
                        System.IO.DirectoryNotFoundException: The system cannot find the path 
                        specified. (Exception from HRESULT: 0x80070003)
                           at TaskScheduler.ITaskService.GetFolder(String Path)
                           at Microsoft.PowerShell.ScheduledJob.ScheduledJobWTS.GetRootFolder()
                           at 
                        Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition.AddToWTS()
                           at 
                        Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition.Register()
                           --- End of inner exception stack trace ---
                           at 
                        Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition.Register()
                           at Microsoft.PowerShell.ScheduledJob.RegisterScheduledJobCommand.Proc
                        essRecord()
                           --- End of inner exception stack trace ---
TargetObject          : Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition
CategoryInfo          : ObjectNotFound: 
                        (Microsoft.Power...edJobDefinition:ScheduledJobDefinition) 
                        [Register-ScheduledJob], RuntimeException
FullyQualifiedErrorId : DirectoryNotFoundWhenRegisteringScheduledJobDefinition,Microsoft.PowerSh
                        ell.ScheduledJob.RegisterScheduledJobCommand
ErrorDetails          : 
InvocationInfo        : System.Management.Automation.InvocationInfo
ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo : {0, 1}

Live Demo