别名模板中的模板参数推导 - typedefing任何成员函数指针

时间:2015-07-27 09:55:03

标签: c++ templates c++11 c++14 template-deduction

虽然answering是一个问题,但我建议使用模板别名来定义成员函数的签名;也就是说,不仅可以键入成员函数,还可以分解出包含该方法的目标类:

template<typename T>
using memberf_pointer = int (T::*)(int, int); 

虽然这似乎涵盖了问题的内容,但我试图将其概括为任意函数参数:

template<typename T, typename... Args>
using memberf_pointer = int (T::*)(Args&&...); 

它与参数演绎问题失败(基本上它假定一个空的arument列表)。这是一个demo

#include <iostream>

class foo
{
public:
  int g (int x, int y) { return x + y ; }
};

template<typename T, typename...Args>
using memberf_pointer = int (T::*)(Args&&...); 

int main()
{
  foo f ;
  memberf_pointer<foo> mp = &foo::g ;
  std::cout << (f.*mp) (5, 8) << std::endl ;
}

这是为什么?有没有办法让它发挥作用?

4 个答案:

答案 0 :(得分:1)

为什么不在这种情况下简单地使用汽车?在这种情况下,拥有模板的唯一优势是能够明确地提供您的类型。

另一方面,如果您希望模板自动推导出一种函数类型,则需要直接对该类型进行参数化。如果您还希望它为您提供所有构建块,最简单的方法是将其专门用于函数或成员函数。例如:

template<typename T> struct memberf_pointer_descriptor;

template<typename TOwner, typename TRet, typename... Args>
struct memberf_pointer_descriptor<TRet(TOwner::*)(Args...)>
{
    // Your stuff goes here.
    using type = TRet(TOwner::*)(Args...);
};

memberf_pointer_descriptor<decltype(&foo::g)>;

或者直接将foo :: g作为参数的函数模板,以减少使用显式decltype的需要。取决于您的需求。

答案 1 :(得分:1)

使您的示例有效的方法如下:

#include <iostream>

class foo
{
public:
    int g(int x, int y) { return x + y; }
};

template<typename T, typename...Args>
using memberf_pointer = int (T::*)(Args...);

int main()
{
    foo f;
    memberf_pointer<foo, int, int> mp = &foo::g;
    std::cout << (f.*mp) (5, 8) << std::endl;
}

它删除了对variadic模板参数的引用,并且在实例化memberf_pointer时它还提供了成员函数参数。但是auto可能是要走的路......

答案 2 :(得分:1)

C ++没有类似于Hindley-Milner类型扣除系统的功能,并且它不适用于您的特定右值分配

memberf_pointer<foo> mp = &foo::g ;

至于一些快速的解决方法,你可以

  1. 删除整个结构并使用auto

    auto mp = &foo::g;
    
  2. 明确提供类型或指针类型

    template<typename T>
    using memberf_pointer = T;
    
    memberf_pointer<decltype(&foo::g)> mp = &foo::g;
    
  3. (CFR)。 Template argument deduction

答案 3 :(得分:1)

问题的标题和正文中的措辞都是非常误导的。在您的示例中,任何地方都会进行零模板扣除。当你写:

memberf_pointer<foo> mp = &foo::g;

memberf_pointer<foo>是一个别名模板,是的,但它是一个特定的实例。由于您提供的确切类型为mp,因此不会进行任何扣减。该行完全等同于:

int (foo:*mp)() = &foo::g;

由于g接受参数的明显原因而无法编译。在赋值语句中获取模板推导的方法是使用auto

auto mp = &foo::g;

mp的类型与您调用的U的类型相同:

template <typename U> void meow(U );
meow(&foo::g);

也就是说,int (foo::*)(int, int)

同样,你可以这样做:

decltype(&foo::g) mp = &foo::g;

哪个会给你与以前相同的类型。

当然,即使您提供了正确的参数列表:

memberf_pointer<foo, int, int> mp = &foo::g;

由于您的别名将rvalue引用添加到两个参数,因此仍然无法编译。 mp的{​​{1}}类型与int (foo::*)(int&&, int&&)不匹配。也许你打算将它作为转发引用的推论,但这不是这里的情况。为了正确使用别名,你必须重写它:

&foo::g

如果我们有一个带有右值引用的成员函数,我们可以明确地提供它:

template<typename T, typename...Args>
using memberf_pointer = int (T::*)(Args...); 

memberf_pointer<foo, int, int> mp = &foo::g;