定义任何成员函数指针的别名中的模板实参演绎
Template argument deduction in alias typedefing any member function pointer
在回答一个问题时,我建议使用模板别名对成员函数的签名进行类型定义;也就是说,不仅要定义成员函数的类型,还要能够分解出包含该方法的目标类:
template<typename T>
using memberf_pointer = int (T::*)(int, int);
虽然这似乎涵盖了所问的问题,但我试图将其推广到任意函数参数:
template<typename T, typename... Args>
using memberf_pointer = int (T::*)(Args&&...);
由于参数演绎问题而失败(基本上它假设一个空的参数列表)。下面是一个演示:
#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 ;
}
为什么会这样?有办法让它起作用吗?
问题的标题和正文中的措辞都很容易误导人。在您的示例中,任何地方都没有进行模板演绎。当你写:
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;
仍然无法编译,因为别名向两个参数都添加了右值引用。mp
的类型是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;
如果有接受右值引用的成员函数,则可以显式地提供它:
class bar
{
public:
int h(int&& x, int&& y) { return x + y ; }
};
memberf_pointer<bar, int&&, int&&> mb = &bar::h;
在这种情况下为什么不直接使用auto呢?在这种情况下使用模板的唯一优点是能够显式地提供类型。
另一方面,如果你想让你的模板自动推断一个函数类型,它需要在该类型上直接参数化。如果您还希望它为您提供所有构建块,最简单的方法是为函数或成员函数专门化它。例子:
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的需要。
使您的示例工作的方法如下:
#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;
}
它删除可变模板形参上的引用,并且在实例化memberf_pointer时也提供成员函数形参。但auto
可能是可行的…
c++没有辛德利-米尔纳类型的演绎系统,它不会为你特定的右值赋值工作
memberf_pointer<foo> mp = &foo::g ;
对于一些快速的变通方法,你可以
只需删除整个结构体并使用
auto
auto mp = &foo::g;
显式提供类型或指针类型
template<typename T> using memberf_pointer = T; memberf_pointer<decltype(&foo::g)> mp = &foo::g;
病死率。模板参数演绎
- 非类型引用形参/实参
- 成员函数指针的模板实参演绎
- 函数和函数作为模板函数的实参
- Const到非Const指针模板实参的转换
- 传递boost::函数,该函数接受一个模板实参作为默认为NULL的形参
- 当实参是初始化列表而形参是引用时,重载解析
- 函数模板中返回类型的模板实参演绎
- ostream_iterator的模板实参-每个元素都是pair
- c++——关于使用默认实参的困惑
- std::shared_ptr、继承和模板实参演绎的问题
- 将操作符转换为模板实参的特化
- 使用模板模板形参时,模板实参推导失败
- 带有const实参的c++构造函数
- c++ 17中关于类模板实参演绎的问题
- 用const实参重载实参演绎的c++模板函数
- 定义任何成员函数指针的别名中的模板实参演绎
- c++中转换函数模板实参演绎的含义
- 函数指针的形参类型的模板实参演绎涉及未演绎的形参包
- 替换在模板实参演绎中是如何工作的
- 从函数指针的实参中演绎出c++模板类型