我有一个代码:
class Factory
{
public:
template<typename ...Args>
static void testFunc(Args&& ...args)
{
cout << "inside function";
}
};
是否可以创建指向 testFunc 的指针? 我所能做的就是像这样定义:
// main
void(*pFunc)() = &Factory::testFunc;
pFunc();
这有效,但我不能传递可变数量的参数,如下所示:
void(*pFunc)(WHAT_TO_TYPE_HERE?) = &Factory::testFunc;
pFunc(10, false, 'a', 11.5);
P.S。:省略号(...)每件事都有效。
答案 0 :(得分:3)
是否可以创建指向
的指针testFunc
?
testFunc
的声明定义了一系列函数,由Args
参数化。每个函数都有自己的内存地址。因此,您只能指向testFunc
定义的特定功能之一,例如testFunc<int, double>
或testFunc<>
。
而不是编写以下内容来获取指向testFunc
void(*pFunc)() = &Factory::testFunc;
你应该写
void(*pFunc)() = &Factory::testFunc<>;
因为没有Factory::testFunc
的{{1}}是重载集,而不是函数。
答案 1 :(得分:1)
答案:
void(*pFunc)(WHAT_TO_TYPE_HERE?) = &Factory::testFunc;
pFunc(10, false, 'a', 11.5);
是:
void (*pFunc)(int&&, bool&&, char&&, double&&) =
&Factory::testFunc<int, bool, char, double>;
由于testFunc
定义了一整套函数,因此您不能只使用一个函数指针来指向所有函数。你必须说出你正在使用函数指针的那个。
答案 2 :(得分:1)
你可以做到。你只需要:
testFunc
只是一个模板(真正意义上的单词定义),您需要使用该模板来构建一个真实函数(这是<>
所做的;它指定了编译器使用模板构建实际函数所需的所有部分)&&
)#include <iostream>
// Ignore this printHelper stuff; it just prints out the arguments
static void printHelper()
{
}
template <typename T>
static void printHelper(T&& arg)
{
std::cout << arg;
}
template<typename T, typename ...Args>
static void printHelper(T&& arg, Args&& ...args)
{
std::cout << arg << ", ";
printHelper(args...);
}
class Factory
{
public:
template<typename ...Args>
static void testFunc(Args&& ...args)
{
std::cout << "inside function; args are: ";
printHelper(args...);
std::cout << std::endl;
}
};
int main()
{
void (*pFunc1)() = &Factory::testFunc<>;
pFunc1();
void (*pFunc2)(int&&, char&&, double&&) = &Factory::testFunc<int, char, double>;
pFunc2(1, 'a', 3.14);
}
答案 3 :(得分:1)
如果你只想要一个指向一个模板函数实例的函数指针的指针,可以用这些参数调用它们:
void(*pFunc)(WHAT_TO_TYPE_HERE?) = &Factory::testFunc;
pFunc(10, false, 'a', 11.5);
然后WHAT_TO_TYPE_HERE
变为
void(*pFunc)(int&&, bool&&, char&&, double&&) = &Factory::testFunc;
pFunc(10, false, 'a', 11.5);
现在,一个缺点是我们已经修复了函数指针中每个参数的rvalue / lvalue状态,这很烦人。
所以这个助手很有用:
template<class Sig, class Function>
struct testfunc_as_function_ptr;
template<class R, class...Args>
struct testfunc_as_function_ptr {
R(*)(Args...) operator()() const {
return [](Args...args){ return Factory::testFunc(std::forward<Args>(args)...); };
}
};
这是非常迟钝的,但确实会给你:
void(*pFunc)(int,bool,char,double) = testfunc_as_function_ptr<void(int, bool, char, double)>{}();
您可以选择签名,如果签名与调用testFunc
兼容,则可以使用。
但是,如果你想要一个指向ENTIRE模板函数的指针,而不仅仅是它的一个实例:
这是nary调度问题。
要意识到的第一件事是模板不是&#34;事物&#34;在C ++中。模板制作的东西。模板类使类 - 模板函数生成函数。
功能模板不是功能。它是生成函数的模板。
所以你的template<class...Args> void testFunc(Args&& ...args)
不是一个功能。它是关于如何产生函数的指令 - 事实上,指令如何产生任意数量的不同函数。这些功能都是&#34;重载&#34;彼此。
对于函数,当你调用它们时,从参数自动生成重载,然后重载决策启动(可能会消除生成的重载,如果例如有一个非模板生成的函数也匹配)。
指针(主要)是运行时构造,指向函数的指针必须指向实际的&#34;&#34; (实际功能)。它不能指向模板。
现在,void testFunc(...)
是一个实际的功能。无论传递给它的参数是什么,都会创建并运行相同的函数。所以你可以指向void testFunc(...)
。
因此,虽然我们不能有指向模板的指针,但您可以创建指向可以分派到模板的构造(对象)的指针。但是,这要求在创建构造时确定调度,并且调用该构造只能到达那些每个确定的实例。
这是一种nary dispatch - 你调用的重载由你传递给函数的参数决定。
C ++不支持在对象中存储代码生成模板。您可以将其存储在类型(类)中,但不能存储在实际对象中。
我们经常可以通过认识到模板函数的主体可能不需要关于Args...
的所有内容来解决这个问题。例如,模板函数的主体可能只需要学习如何将给定的Arg
转换为字符串?
在这种情况下,我们可以创建一个如下所示的界面:
struct printable { virtual std::string to_string() const = 0; ~printable(); };
using printer = void(*)(std::vector<std::unique_ptr<printable>>);
和printer
是一个指向vector
printable
个T
指针的函数的指针。然后,我们可以编写采用任意类型printable
并使其成为Args...
的代码。
这需要知道我们试图产生的功能需要了解boost::any
。
您可以将函数指针作为指向类型擦除的可迭代范围的指针,等同于void (*)(...)
,然后让主体确定实际需要的类型并进行内省。这是类型安全的等效于{{1}} C风格的变量,其中被调用的函数必须执行所有类型体操以确保手动工作。
答案 4 :(得分:1)
您的问题是&Factory::testFunc
指的是重载集,而不是单个函数。
过载集是否包含(或包含)模板函数是不重要的,歧义意味着编译器不知道该怎么做。
只需static_cast
指向所需类型的函数(或在另一个上下文中使用它,使所需类型明显),如下所示:
void(*pFunc)() = &Factory::testFunc;
f( (void(*)())&Factory::testFunc); // static_cast to get the right overload
见coliru:http://coliru.stacked-crooked.com/a/13571ddf095df15f
当然,因为它是一个模板函数,你可以通过显式指定参数来从过载集中选择一个函数,如下所示:
void(*pFunc)() = &Factory::testFunc<>;