C++ 是否可以获取函数模板的隐式实例化的地址?
我想知道是否有任何方法可以获得由一组特定参数生成的函数模板的实例化地址C++ 是否可以获取函数模板的隐式实例化的地址?,c++,templates,c++11,C++,Templates,C++11,我想知道是否有任何方法可以获得由一组特定参数生成的函数模板的实例化地址 #include <iostream> template <typename T> class A {}; template <typename T, typename T2> int hello(A<T> a, A<T2> b, int c) { return 69; } int main() { A<int> a;
#include <iostream>
template <typename T>
class A {};
template <typename T, typename T2>
int hello(A<T> a, A<T2> b, int c)
{
return 69;
}
int main()
{
A<int> a;
A<float> b;
std::cout << (&hello)(a, b, 3) << "\n";
return 0;
}
#包括
模板
A类{};
模板
int你好(A,A,b,int c)
{
返回69;
}
int main()
{
A A;
A b;
std::cout根据参数确定要调用的函数的过程称为重载解析,标准列表列出了在哪些情况下使用该函数:
13.3过载分辨率[超过.match]
2重载解析选择要在语言中的七种不同上下文中调用的函数:
(2.1)——调用函数调用语法中命名的函数(13.3.1.1.1)
(2.2)--调用函数调用运算符、函数转换函数指针、函数转换函数指针引用或名为
函数调用语法(13.3.1.1.2)
(2.3)——调用表达式中引用的运算符(13.3.1.2)
(2.4)——调用构造函数直接初始化类对象(13.3.1.3)
(2.5)——调用用户定义的转换,用于类对象(13.3.1.4)的副本初始化(8.5)
(2.6)——调用转换函数,从类类型的表达式初始化非类类型的对象(13.3.1.5);以及
(2.7)——调用转换函数,以转换为参考(8.5.3)将直接绑定到的glvalue或类prvalue(13.3.1.6)
其中,唯一适用于常规函数的是2.1,它需要一个f(args)
上下文,该上下文只告诉调用方结果
所以,你所要求的无法实现。无论如何,不完全是这样
现在,根据您想要实现的目标,有一些事情是可能的:
如果您知道确切的签名,则可以获取指向函数的指针:给定模板int hello(a,a b)
,您可以使用以下内容获取地址:static\u cast(hello)
。但是,要使其起作用,您需要知道返回类型(可以使用decltype
),并且您需要知道参数类型(可能不同于参数类型,并且无法可靠地获取)
还可以获取指向函数的指针,该函数在调用时将具有与hello
相同的效果:
auto callable = +[](A<int> a, A<int> b) { return hello(a, b); };
autocallable=+[](aa,ab){返回hello(A,b);};
[](A A,A b){return hello(A,b);}
创建一个没有任何捕获的lambda,并且没有任何捕获的lambda可以隐式转换为匹配类型的函数指针。+
强制使用该转换,而不需要指定类型
但是,该地址与hello
地址不同,因此可能不适合后续比较
这是你能得到的最好的了。我试过:
//A和hello定义为OP
int main()
{
A A;
A b;
decltype(hello(a,b,3))(*pf)(decltype(a),decltype(b),decltype(3))=hello;
std::cout@hvd:AFAIK,在不知道要包装的函数的签名的情况下,不能声明lambda(lambda不能被模板化)。但是可以使用带有静态方法的中间类:
#include <functional>
#include <iostream>
template<class A>
void func(A a, int b)
{
std::cout << "a=" << a << " b=" << b << "\n";
}
template<class... A>
class proxy_func
{
public:
static auto call(A... args) -> decltype(func(args...))
{
return func(args...);
}
};
template<template<class...> class P, class... User>
void* addr(User... user)
{
return (void*)&P<User...>::call;
}
template<template<class...> class P, class... User>
auto call(User... user) -> decltype(P<User...>::call(user...))
{
return P<User...>::call(user...);
}
template<class T>
void test()
{
T value = 1;
printf("func > %p\n", &func<T>);
printf("func > ");
func(value, 1);
printf("proxy> %p\n", &proxy_func<T, int>::call);
printf("proxy> ");
proxy_func<T, int>::call(value, 1);
printf("auto > %p\n", addr<proxy_func>(value, 1));
printf("auto > ");
call<proxy_func>(value, 1);
}
int main(int argc, char **argv)
{
printf("==int==\n");
test<int>();
printf("==long==\n");
test<long>();
}
当然,这需要声明一个通用代理,该代理知道目标函数的名称(其他什么都不知道),而作为@JavierCabezasRodríguez的解决方案,这可能是不可接受的
PS:对不起,我没有把它作为评论发表,但我没有足够的声誉
编辑
使用代理类而不是lambda就不需要知道参数的数量,这样您就可以使用一种骇人听闻的宏方法来包装任何目标函数:
#define proxy(f) \
template<class... A> \
class proxy_ ## f \
{ \
public: \
static auto call(A... args) -> decltype(f(args...)) \
{ \
return f(args...); \
} \
}
proxy(func);
#定义代理(f)\
模板\
类代理35;##f\
{ \
公众:\
静态自动调用(A…args)->decltype(f(args…)\
{ \
返回f(args…)\
} \
}
代理(func);
&hello
?@Borgeader:这不太正确,hello
的模板参数将是int
,但无法按原样从a
获取int
。@Lalaland:参数可以是任何东西,不一定是类或类模板。@FilipRoséen refp:有方法获取返回类型,但是要获得地址,需要知道隐式转换后的参数,而在C++中没有办法做到这一点(如果你找到一个反例,那将是开创性的,我会很高兴看到它)。(我考虑的是相关的。在这种情况下,这可能是可能的,因为只有一个模板函数,没有重载或转换)@MooingDuck甚至不是C++17。我们在库基础知识TS中确实获得了调用类型特征,但它们只对函数对象有效,而不是泛型重载集。可能需要解释一下+
。这有点模糊。如果复制a
有任何副作用,则lambda指针的效果与hello不同。如果移动,则如果移动向量有副作用(或者如果hello
以不同的方式对待右值),则不会产生相同的效果。如果hello
通过引用进行,则对对象所做的任何更改都不会传播到lambda解决方案中。所有这些基本上都需要检查实现
g++ -std=c++11 -o /tmp/test /tmp/test.cpp && /tmp/test
==int==
func > 0x400a8d
func > a=1 b=1
proxy> 0x400ae6
proxy> a=1 b=1
auto > 0x400ae6
auto > a=1 b=1
==long==
func > 0x400b35
func > a=1 b=1
proxy> 0x400b91
proxy> a=1 b=1
auto > 0x400b91
auto > a=1 b=1
#define proxy(f) \
template<class... A> \
class proxy_ ## f \
{ \
public: \
static auto call(A... args) -> decltype(f(args...)) \
{ \
return f(args...); \
} \
}
proxy(func);