2017-07-02 93 views
1

我需要將異步函數調用轉換爲同步函數調用。有很多這樣的功能,所以我想使用模板進行轉換。下面是一個簡化程序的樣子:使用可變參數模板調用成員函數

#include <functional> 
#include <future> 
#include <iostream> 

using namespace std; 

using CallBack = function<void (int)>; 

class C { 
    template<typename... Ts> 
    int InvokeAsync(void (C::*async)(Ts..., CallBack), Ts... args) { 
     promise<int> p; 
     auto cb = [&p](int r) { p.set_value(r); }; 
     async(args..., cb); 
     auto f = p.get_future(); 
     f.wait(); 
     return f.get(); 
    } 
public: 
    void Async(int x, int y, CallBack cb) { 
     cb(x + y); 
    } 
    int Sync(int x, int y) { 
     return InvokeAsync(&C::Async, x, y); 
    } 
    void Async(int x, CallBack cb) { 
     cb(x); 
    } 
    int Sync(int x) { 
     return InvokeAsync(&C::Async, x); 
    } 
}; 

該程序不編譯。

GCC

$ g++ --version 
g++ (GCC) 5.4.0 
Copyright (C) 2015 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
$ g++ -c -std=c++14 -o x.o x.cc 
x.cc: In member function ‘int C::Sync(int, int)’: 
x.cc:24:43: error: no matching function for call to ‘C::InvokeAsync(<unresolved overloaded function type>, int&, int&)’ 
     return InvokeAsync(&C::Async, x, y); 
             ^
x.cc:11:9: note: candidate: template<class ... Ts> int C::InvokeAsync(void (C::*)(Ts ..., CallBack), Ts ...) 
    int InvokeAsync(void (C::*async)(Ts..., CallBack), Ts... args) { 
     ^
x.cc:11:9: note: template argument deduction/substitution failed: 
x.cc:24:43: note: mismatched types ‘CallBack {aka std::function<void(int)>}’ and ‘int’ 
     return InvokeAsync(&C::Async, x, y); 
             ^
x.cc:24:43: note: mismatched types ‘CallBack {aka std::function<void(int)>}’ and ‘int’ 
x.cc:24:43: note: could not resolve address from overloaded function ‘&((C*)this)->*C::Async’ 
x.cc: In member function ‘int C::Sync(int)’: 
x.cc:30:40: error: no matching function for call to ‘C::InvokeAsync(<unresolved overloaded function type>, int&)’ 
     return InvokeAsync(&C::Async, x); 
             ^
x.cc:11:9: note: candidate: template<class ... Ts> int C::InvokeAsync(void (C::*)(Ts ..., CallBack), Ts ...) 
    int InvokeAsync(void (C::*async)(Ts..., CallBack), Ts... args) { 
     ^
x.cc:11:9: note: template argument deduction/substitution failed: 
x.cc:30:40: note: mismatched types ‘CallBack {aka std::function<void(int)>}’ and ‘int’ 
     return InvokeAsync(&C::Async, x); 
             ^
x.cc:30:40: note: mismatched types ‘CallBack {aka std::function<void(int)>}’ and ‘int’ 
x.cc:30:40: note: could not resolve address from overloaded function ‘&((C*)this)->*C::Async’ 

$ clang++ --version 
clang version 3.7.1 (tags/RELEASE_371/final) 
Target: x86_64-apple-darwin16.6.0 
Thread model: posix 
$ clang++ -c -std=c++14 -o x.o x.cc 
x.cc:24:16: error: no matching member function for call to 'InvokeAsync' 
     return InvokeAsync(&C::Async, x, y); 
       ^~~~~~~~~~~ 
x.cc:11:9: note: candidate template ignored: substitution failure [with Ts = <int, int>] 
    int InvokeAsync(void (C::*async)(Ts..., CallBack), Ts... args) { 
     ^
x.cc:14:9: error: called object type 'void (C::*)(int, CallBack)' is not a function or function pointer 
     async(args..., cb); 
     ^~~~~ 
x.cc:30:16: note: in instantiation of function template specialization 'C::InvokeAsync<int>' requested here 
     return InvokeAsync(&C::Async, x); 
      ^
2 errors generated. 

,該怎麼辦錯了:這裏是由gcc和鐺,分別產生的錯誤?

回答

3

首先,你應該做的template parameter pack參數最後一個參數列表中,即

template<typename... Ts> 
int InvokeSync(void (C::*async)(CallBack, Ts...), Ts... args) { 

然後

void Async(CallBack cb, int x, int y) 
void Async(CallBack cb, int x) 

其次,當上async您應該指定實例調用被叫做,即

(this->*async)(cb, args...); 

LIVE

0

您正在過度約束函數類型。更簡單的版本將會:

template<typename F typename... Ts> 
int InvokeAsync(F C::*async, Ts... args) { 
    promise<int> p; 
    auto cb = [&p](int r) { p.set_value(r); }; 
    (this->*async)(args..., cb); 
    auto f = p.get_future(); 
    f.wait(); 
    return f.get(); 
} 
+1

你試過了嗎?重載解析如何在兩個版本的Async之間進行選擇? –

+0

@ n.m。公平點,我沒有。這需要在呼叫站點進行明確的演員表演,這並不比第一次通過回調更好。 –