使用std :: apply应用可变参数函数(Applying a variadic function with std::apply)
是否可以使用std :: 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>
?Is it possible to apply a variadic function to a tuple with std::apply?
For example, the following code works fine with 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; }
But if I try to apply a variadic function:
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; }
the compiler complains that it cannot deduce template arguments of
vprint
. OK, let's write them explicitly:std::experimental::apply(vprint<std::string, std::string>, t);
Now the compiler ends up with some obscure errors which expose standard library internals.
I wrote my own implementation of
std::apply
in C++11 and I understand why it can't deduce arguments of the variadic function template. But, in theory,std::apply
has all the information needed for that deduction.So is the application of variadic functions a not yet implemented feature in GCC6? Will C++17-compatible compilers allow such application? If not, will they allow application of instantiated variadic template functions, like
vprint<std::string, std::string>
?
原文:https://stackoverflow.com/questions/40523334
最满意答案
Stephen Toub在他的博客上涵盖了所有各种方法及其相应的缺点 。
只有两种通用解决方案,两者都不理想:
- 复制图层中的逻辑; 让您的同步方法调用库中的同步方法。 (这假设库具有同步方法以及异步)。
- 阻止返回的任务,类似于您的示例代码。 这假设库始终使用
ConfigureAwait(false)
,这是一个不受控制的假设。 如果库是无上下文的,那么将异步调用抛出到Task.Run
并阻塞该任务可能会更安全。 此外,确保在阻止任务时解除异常,因为Wait
或Result
将在AggregateException
包装异常。这两种解决方案都存在一些严重的维护问题。
Stephen Toub covers all the various approaches with their corresponding drawbacks on his blog.
There are only two general-purpose solutions, neither of which is ideal:
- Duplicate the logic in your layer; have your synchronous methods call the synchronous methods in the library. (This assumes that the library has synchronous methods as well as asynchronous).
- Block on the returned task, similar to your example code. This assumes that the library always uses
ConfigureAwait(false)
, an assumption that is out of your control. If the library is context-free, then it may be safer to throw the asynchronous invocation into aTask.Run
and block on that task instead. Also, ensure you unwrap exceptions when blocking on a task, sinceWait
orResult
will wrap exceptions in anAggregateException
.Both of these solutions have somewhat serious maintenance problems.
相关问答
更多-
混淆了从异步方法同步调用CPU绑定方法(Confusion about calling CPU-bound methods synchronously from an async method)[2022-12-27]
如图所示,从当前线程调用它是否是最佳做法? 如果当前线程在异步操作正在进行时是空闲的,为什么要使用不同的线程? 什么会使这个线程比你已经使用的更好? 想到有关DoIndependentWork实际上在做什么的问题。 如果它在HTTP请求完成之前完成至关重要,那么我会同步调用它。 如果在HTTP请求完成之前工作并不是至关重要的,那么我会寻找一个完全不同的解决方案。 在ASP.NET中使用Task.Run是很危险的。 请记住,ASP.NET中的延续在任意线程池线程上运行。 Is it the best prac ... -
如何在Windows Phone 8中同步调用异步方法(How to call asynchronous method synchronously in Windows Phone 8)[2021-11-20]
首先避免使用异步void方法,因为你不能轻易等待它的完成。 相反,返回Task ,在async方法内,您不需要做一些特殊的事情来返回Task 。 编译器为您完成所有工作。 您需要等待对HttpClient.PostAsync的调用,这应该足以保持UI响应。 private static async Task CallService(System.Uri uri) { using (HttpClient client = new HttpClient()) { client.D ... -
这是一个解决方法,我发现,适用于所有情况(包括暂停调度员)。 这不是我的代码,我仍然在努力完全理解它,但它的工作。 可以使用: customerList = AsyncHelpers.RunSync
- >(() => GetCustomers()); 代码来自这里 public static class AsyncHelpers
{
///
/// Execute's an async Task method which has a voi ... -
您需要在同步方法的最后添加一些内容,以告诉它等待另一个呼叫完成。 我假设你的异步方法将有一个事件告诉调用者何时完成。 如果是这样的话,我会建议使用类似于ManualResetEvent的东西,在同步线程中等待它,并将其设置在异步的Finish事件接收器中。 例: public void DoSomething(Action
actionToPerformOnComplete) { ManualResetEvent mre = new ManualResetEvent(false); D ... -
不要投票。 使用内置的同步功能。 RestResponse
response = null; var executedCallBack = new AutoResetEvent(false); client.ExecuteAsync(request, (RestResponse aSyncResponse)=>{ response = aSyncResponse; executedCallBack.Set(); }); executedCallBack.WaitOne(); / ... -
NSStream是一个抽象类,既不会将数据读取也不会将数据写入流中。 要实际访问数据,您需要一个具体的子类,例如NSInputStream或NSOutputStream (或NSOutputStream的自定义子类)。 要读取NSInputStream的数据,请调用read:maxLength: . 您可能希望使用hasBytesAvailable轮询流,询问是否有任何新数据可用。 NSOutputStream具有类似的write:maxLength:和hasSpaceAvailable方法。 iOS文档强 ...
-
在单元测试中同步调用异步方法是不正确的吗?(Is it incorrect to call async methods synchronously in unit tests?)[2023-05-21]
必须为async方法调用异步方法异步的单元测试? 不,但这样做是最自然的。 如果它使用Task.Run()同步调用异步方法,会丢失什么? 真的没什么。 它的性能稍差,但在某种程度上你可能永远不会注意到。 您可能希望使用GetAwaiter().GetResult()而不是Result来避免失败测试中的AggregateException包装。 你也可以直接调用这个方法; 无需将其包装在Task.Run 。 他们说这种缺乏支持是有正当理由的,我并不反对。 哦,我当然不同意他们。 :) 这是否意味着他们无法单元 ... -
同步调用异步方法(Invoking an async method synchronously)[2022-09-06]
Stephen Toub在他的博客上涵盖了所有各种方法及其相应的缺点 。 只有两种通用解决方案,两者都不理想: 复制图层中的逻辑; 让您的同步方法调用库中的同步方法。 (这假设库具有同步方法以及异步)。 阻止返回的任务,类似于您的示例代码。 这假设库始终使用ConfigureAwait(false) ,这是一个不受控制的假设。 如果库是无上下文的,那么将异步调用抛出到Task.Run并阻塞该任务可能会更安全。 此外,确保在阻止任务时解除异常,因为Wait或Result将在AggregateException ... -
SignalR .Net客户端 - 如何同步和异步调用(SignalR .Net client - how to invoke synchronously and asynchronously)[2022-03-24]
如果要编写异步代码,则应使用async / await 。 我在我的博客上有一个介绍,最后有一些后续资源。 当您启动异步操作(例如, Invoke )时,您将获得一个任务。 Task类型用于没有返回值的异步操作, Task用于具有返回值的异步操作。 这些任务类型可以在操作完成时指示您的代码,以及它是否成功完成或出错。 虽然你可以使用Task.Wait和Task .Result ,但我不推荐它们。 首先,它们在AggregateException包装任何异常,这使得您的错误处理代码更加麻烦。 使用a ... -
我建议您始终使用异步编程。 如果您遇到某种资源问题(即,不允许对单个数据库进行多次查询),那么您应该构建代码以便不会发生(例如,在操作正在运行时禁用UI按钮)。 或者,如果必须,您可以使用SemaphoreSlim来限制async代码: private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1); public async Task UploadCurrentXMLAsync() { await _mutex.WaitAsync(); t ...