2016-03-07 66 views
1

我想使用指向成员函数指针和参数包的指针调用函数。下面给出代码:使用参数包推导函数参数类型

class DemoClass { 
public: 
    void Printer(const DemoClass& sc, const int& i) { 
    } 
}; 



template<typename R, typename T, typename ... Args/*, typename ... Params*/> 
void MakeMemberActionDemoClass(R(T::*memberFunction)(Args...), Args&& ... args) 
{ 
} 

int main() 
{ 
    DemoClass d; 
    int z; 
    MakeMemberActionDemoClass(&DemoClass::Printer, d, z); 
} 

我获得以下错误:

error C2782: 'void MakeMemberActionDemoClass(R (__thiscall T::*)(Args...),Args &&...)' : template parameter 'Args' is ambiguous 

1>   could be 'const DemoClass&, const int&' 
1>   or  'DemoClass&, int&' 

如果我删除& &在MakeMemberActionDemoClass的最后一个参数,仅在误差差值如下:

1>   could be 'const DemoClass&, const int&' 
1>   or  'DemoClass, int' 

什么我应该这样做,以便正确推导参数类型?

由于提前,

+1

使用'R(T :: * memberFunction)(Args ...),Params && ... args',使它们分别被推导出来 –

回答

2

Args两个实例是在一个可推论上下文。它们必须产生相同的类型,否则你的编译器会抱怨它不明确。

一种方法是在一个或另一个上下文中阻止演绎。另一种方法是停止连接它们。

template<class T>struct tag_t{using type=T;}; 
template<class Tag>using type_t=typename Tag::type; 

template<class T>using block_deduction=type_t<tag_t<T>>; 

template<class R, class T, class...Args> 
void MakeMemberActionDemoClass(
    R(T::*memberFunction)(Args...), 
    block_deduction<Args>... args 
) 
{ 
} 

这具有可能将值复制两次的代价。

template<class R, class T, class...Args, class...Params> 
auto MakeMemberActionDemoClass(
    R(T::*memberFunction)(Args...), 
    Params&&... params 
) 
->decltype((std::declval<T*>()->*memberFunction)(std::declval<Params>()...)) 
{ 
} 

将正确地推断他们,让你完美向前进入memberFunction和SFINAE及早检测到过载故障。

+0

谢谢。请注意我不能使第二个解决方案工作 - 一个decltype。 Visual Studio 2013(更新5)不断给我一些错误。另外,要注意的是,在第一个解决方案中,如果你想创建元组,你将需要使用std :: forward_as_tuple。 – user1578026

+0

@ user1578026我修正了第二个错字。可能有帮助。但VS2013和2015对'decltype'的支持很差,所以... – Yakk

+0

@Piotr该死的你'操作员 - > *'我的老对手 – Yakk