use*_*751 11 c++ templates variadic-templates c++11
根据我的理解,以下程序显然应该打印:
1.0 hello world 42
Run Code Online (Sandbox Code Playgroud)
但是,它无法编译.为什么?
#include <iostream>
#include <string>
using namespace std;
template<class... InitialArgTypes>
void CallWithExtraParameter(void (*funcPtr)(InitialArgTypes..., int), InitialArgTypes... initialArgs)
{
(*funcPtr)(initialArgs..., 42);
}
void Callee(double a, string b, int c)
{
cout << a << " " << b << " " << c << endl;
}
int main()
{
CallWithExtraParameter<double, string>(Callee, 1.0, string("hello world"));
}
Run Code Online (Sandbox Code Playgroud)
prog.cpp: In function 'int main()':
prog.cpp:18:75: error: no matching function for call to 'CallWithExtraParameter(void (&)(double, std::string, int), double, std::string)'
CallWithExtraParameter<double, string>(Callee, 1.0, string("hello world"));
^
prog.cpp:6:6: note: candidate: template<class ... InitialArgTypes> void CallWithExtraParameter(void (*)(InitialArgTypes ..., int), InitialArgTypes ...)
void CallWithExtraParameter(void (*funcPtr)(InitialArgTypes..., int), InitialArgTypes... initialArgs)
^
prog.cpp:6:6: note: template argument deduction/substitution failed:
prog.cpp:18:75: note: mismatched types 'int' and 'double'
CallWithExtraParameter<double, string>(Callee, 1.0, string("hello world"));
^
Run Code Online (Sandbox Code Playgroud)
首先,"hello world"不会推断std::string,它会推断const char*,哪个不匹配Callee,所以让我们修复你的通话"hello world"s而不是通过.
其次,有一个类型的参数似乎存在一些问题:
void (*funcPtr)(InitialArgTypes..., int)
Run Code Online (Sandbox Code Playgroud)
这显然是在非演绎语境和可推导语境之间的某种不确定性 - 因为它不是非演绎语境(否则InitialArgTypes...将从其他参数中推断出来)并且它不可推导(因为它仍然失败).因此,让我们更进一步,明确地将其作为一个非演绎的背景:
template <class T> struct identity { using type = T; };
template <class T> using identity_t = typename identity<T>::type;
template <class... InitialArgTypes>
void CallWithExtraParameter(void (*funcPtr)(identity_t<InitialArgTypes>..., int),
InitialArgTypes... initialArgs)
{
(*funcPtr)(initialArgs..., 42);
}
Run Code Online (Sandbox Code Playgroud)
现在,InitialArgTypes...将从最后传递的论点中推断出来.这是我们想要的,所以这是有效的:
CallWithExtraParameter(Callee, 1.0, "hello world"s);
Run Code Online (Sandbox Code Playgroud)