【问题标题】:Variadic Templates, Perfect Forwarding to functions with default arguments可变参数模板,完美转发到具有默认参数的函数
【发布时间】:2012-01-06 14:18:58
【问题描述】:

我一直在使用可变参数模板,它在 C 和 C++ 之间的接口中充当异常防火墙。模板只接受一个函数,后跟 N 个参数,然后在 try catch 块中调用该函数。这一直运行良好,不幸的是,我现在要调用的函数之一需要一个额外的默认参数。结果函数名没有解析,模板编译失败。

错误是:

perfect-forward.cpp: 在函数‘void FuncCaller(Func, Args&& ...) [with Func = void (*)(const std::basic_string<char>&, double, const std::vector<int>&), Args = {const char (&)[7], double}]’:
perfect-forward.cpp:69:41: 从这里实例化
perfect-forward.cpp:46:4: 错误:函数参数太少

简化版代码如下:

template< class Func, typename ...Args >
void FuncCaller( Func f, Args&&... params )
{
   try
   {
       cout << __func__ << " called\n";
       f(params...);
   }
   catch( std::exception& ex )
   {
       cout << "Caught exception: " << ex.what() << "\n";
   }
}

void Callee( const string& arg1, double d, const vector<int>&v = vector<int>{} )
{
   cout << __func__ << " called\n";
   cout << "\targ1: " << arg1 << "\n";
   cout << "\td: " << d << "\n";
   cout << "\tv: ";
   copy( v.begin(), v.end(), ostream_iterator<int>( cout, " "  ) );
   cout << "\n";
}

int main()
{
   vector<int> v { 1, 2, 3, 4, 5 };

   FuncCaller( Callee, "string", 3.1415, v );
   FuncCaller( Callee, "string", 3.1415 );  **// Fails to compile**

   return 0;
} 

这段代码应该工作还是我对编译器的期望太高了?

注意:我已经使用具有默认参数的构造函数测试了完美转发的使用,并且代码可以按预期编译和工作,

即:

template<typename TypeToConstruct> struct SharedPtrAllocator 
{
    template<typename ...Args> shared_ptr<TypeToConstruct> 
        construct_with_shared_ptr(Args&&... params) {
        return std::shared_ptr<TypeToConstruct>(new TypeToConstruct(std::forward<Args>(params)...));
    };
};

在使用 2 或 3 个参数调用 cfollowing 构造函数时有效...

MyClass1( const string& arg1, double d, const vector<int>&v = vector<int>{} )

【问题讨论】:

  • (顺便说一句,应该是f(std::forward&lt;Args&gt;(params)...);。)

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


【解决方案1】:

我认为没有任何方法可以实现。默认参数值不是函数签名的一部分。它们只是在您逐字调用函数时由编译器扩展的代码生成简写。同样,std::bind 也不会选择默认参数。

【讨论】:

  • 我认为这些行有点长...出于兴趣,为什么转发到带有默认参数的构造函数有效?
  • 好吧,您可以直接调用该函数,这就是您的代码所做的(如果您解开所有模板参数替换)。但在最初的问题中,函数类型本身是推导出来的,这就是你失去默认参数的地方。
  • @KerrekSB - 您能否更详细地解释您对解开模板参数替换的评论?
  • @tuskcode:我的意思是当您填写模板的实际用例时,例如SharedPtrAllocator&lt;MyClass1&gt;().construct_with_shared_ptr("foo", 1.5),那么模板专业化在其定义中会显示new MyClass1("foo", 1.5)(这就是“解开”我想到了),因此默认参数在该上下文中可用。相比之下,原始代码总是说f(params...),它从不Callee(params...)。换句话说,FuncCaller 的参数是函数,而不是函数声明。并且 value 不包含默认参数。
猜你喜欢
  • 1970-01-01
  • 2013-01-06
  • 1970-01-01
  • 2011-09-23
  • 1970-01-01
  • 2019-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多