2016-11-10 67 views
3

是否可以将变量函数应用于std :: apply的元组?应用std :: apply的变量函数:: apply

例如,下面的代码工作正常GCC 6.2.1:

void print_t(std::string i, std::string j) { 
    std::cout << i << " " << j << std::endl; 
} 

int main() { 
     std::tuple<std::string, std::string> t{"ab", "cd"}; 
     std::experimental::apply(print_t, t); 
     return 0; 
} 

但是,如果我尝试应用可变参数函数:

template<typename T> 
void vprint(T && t) { 
    std::cout << std::forward<T>(t) << std::endl; 
} 

template<typename T, typename ... Ts> 
void vprint(T && t, Ts ... ts) { 
    std::cout << std::forward<T>(t) << " "; 
    vprint<Ts...>(std::forward<Ts>(ts)...); 
} 

int main() { 
     std::tuple<std::string, std::string> t{"fd", "ab"}; 
     std::experimental::apply(vprint, t); 
     return 0; 
} 

编译器抱怨说,它不能推导出模板参数vprint。好吧,让我们明确地写出它们:

std::experimental::apply(vprint<std::string, std::string>, t); 

现在,编译器结束了一些暴露标准库内部的模糊错误。

我在C++ 11中编写了自己的std::apply实现,并且我理解为什么它不能推导出可变参数函数模板的参数。但是,理论上std::apply具有所有扣除所需的信息。

那么,可变参数函数在GCC6中的应用还没有实现? C++ 17兼容的编译器是否允许这样的应用程序? 如果不是,他们会允许应用实例化的可变参数模板函数,如vprint<std::string, std::string>

回答

6

随着vprint<std::string, std::string>,你必须通过R值引用,所以

std::experimental::apply(vprint<std::string, std::string>, std::move(t)); 

更好的办法是使用仿函数(感谢通用拉姆达):

std::experimental::apply([](auto&&... args) { 
          vprint(std::forward<decltype(args)>(args)...); 
         }, 
         t); 
+0

为什么是第二方案更好? 'std :: move'基本上是对右值引用的强制转换,所以这两个代码片段的语义看起来都是相同的。 – Sergey

+0

@Sergey:第二个继续转发参数,而第一个强制知道元组类型,可能会修改't'(因为print_t通过复制传递)。 – Jarod42

+2

@Sergey我们假设'print_t'不是您想要调用的唯一函数;并且'std :: string &&'参数可以自由移动。你不会在你的实现中移动它。从语义上讲,在移入函数调用之后,没有人应该依赖'std :: string',但是,除非有强有力的保证(比如'get'提供)。 – Yakk