模板 class 中的模板可变参数函数无法编译
Template variadic function in template class won't compile
我正在尝试为模板 class 编写一个函数,它接受一个参数,该参数是一个成员的函数指针 class 在大 [=23= 的私有数据中].当您调用该成员时,它会在较小的 class 上调用该函数。 (混淆吧?)为了演示,我在这里有一个无效的例子:
#include <vector>
#include <iostream>
using namespace std;
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A... args) { // pass in the function we want to call
return (mContainer.*func) (args...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
int main() {
MyClass<int, std::vector<int> > test;;
cout << test.call_me(&std::vector<int>::size) << endl; // works
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4); // doesn't work
return 0;
}
请注意,这不是我的实际代码,而是我正在尝试做的事情的一个小例子。如您所见,我正在尝试调用 'Private' 的 size
成员函数(为了演示,我将其保留在此处 public) vector
class MyClass
里面。这仅在我没有编译器要解压的参数时才有效,但是当我尝试执行插入函数(具有要解压的参数)时,编译器给我一个错误:
.\template.cpp: In function 'int main()':
.\template.cpp:24:71: error: no matching function for call to 'MyClass<int, std::vector<int> >::call_me(<unresolved overloaded function type>, std::vector<int>::iterator, int)'
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4);
^
.\template.cpp:10:10: note: candidate: template<class F, class ... A> auto MyClass<T, C>::call_me(F, A ...) [with F = F; A = {A ...}; T = int; C = std::vector<int>]
auto call_me(F func, A... args) { // pass in the function we want to call
^~~~~~~
.\template.cpp:10:10: note: template argument deduction/substitution failed:
.\template.cpp:24:71: note: couldn't deduce template parameter 'F'
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4);
这与我在实际生产代码中遇到的错误相同,调用不带参数的可变参数函数来解包有效,但如果我提供的不止于此,我会收到相同的错误消息。这是我第一次真正尝试使用 Variadic 模板,因此我们将不胜感激任何建议和帮助。
这里的问题是 insert
是一个重载函数。编译器没有尝试解决您在模板参数推导中想要的重载,因为它无法知道。您必须将函数强制转换为您要使用的重载类型,以便为其指定类型。看起来像
using insert_func_t = std::vector<int>::iterator(std::vector<int>::*)(std::vector<int>::const_iterator, const int&);
test.call_me(static_cast<insert_func_t>(&std::vector<int>::insert), test.mContainer.begin(), 4);
一般来说是
static_cast<return_type(class_name::*)(function_parameters)>(&class_name::function_name)
另一种选择是稍微更改函数并使用 lambda 表达式来表达您想要完成的操作。看起来像
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A... args) { // pass in the function we want to call
return func(mContainer, args...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
int main() {
MyClass<int, std::vector<int> > test;;
test.call_me([](auto& container, auto... args){ container.insert(args...); }, test.mContainer.begin(), 4);
return 0;
}
基本上你不能获取未解析的重载函数的地址,因为编译器将无法选择正确的函数入口点地址。在正常的函数调用期间,编译器会解析重载函数,但是对于像您的模板或 std::bind() 这样的模板,这将不起作用,因为参数用于调用模板函数,而不是您要获取地址的函数。
您可以像这样手动解决过载问题:
using ftype = std::vector<int>::iterator(std::vector<int>::*)
(std::vector<int>::const_iterator, const std::vector<int>::value_type&);
test.call_me((ftype)(&std::vector<int>::insert), test.mContainer.begin(), 4); // works
做这种事情的时候处理函数对象比较容易。它将方法重载问题卸载给编译器。
Lambda 也可以工作(它们是函数对象):
#include <vector>
#include <iostream>
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A&&... args) -> decltype(auto)
{ // pass in the function we want to call
return func(mContainer, std::forward<A>(args)...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
/*
* It's often easier to deal in function objects
*/
struct insert
{
template<class Container, class...Args>
decltype(auto) operator()(Container& cont, Args&&...args) const
{
return cont.insert(std::forward<Args>(args)...);
}
};
struct size
{
template<class Container, class...Args>
decltype(auto) operator()(Container& cont) const
{
return cont.size();
}
};
int main() {
MyClass<int, std::vector<int> > test;;
std::cout << test.call_me(size()) << std::endl; // works
test.call_me(insert(), test.mContainer.begin(), 4); // doesn't work
// or lambdas
auto insert2 = [](auto& container, auto&&...args) -> decltype(auto)
{
return container.insert(std::forward<decltype(args)>(args)...);
};
test.call_me(insert2, test.mContainer.begin(), 5);
return 0;
}
我正在尝试为模板 class 编写一个函数,它接受一个参数,该参数是一个成员的函数指针 class 在大 [=23= 的私有数据中].当您调用该成员时,它会在较小的 class 上调用该函数。 (混淆吧?)为了演示,我在这里有一个无效的例子:
#include <vector>
#include <iostream>
using namespace std;
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A... args) { // pass in the function we want to call
return (mContainer.*func) (args...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
int main() {
MyClass<int, std::vector<int> > test;;
cout << test.call_me(&std::vector<int>::size) << endl; // works
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4); // doesn't work
return 0;
}
请注意,这不是我的实际代码,而是我正在尝试做的事情的一个小例子。如您所见,我正在尝试调用 'Private' 的 size
成员函数(为了演示,我将其保留在此处 public) vector
class MyClass
里面。这仅在我没有编译器要解压的参数时才有效,但是当我尝试执行插入函数(具有要解压的参数)时,编译器给我一个错误:
.\template.cpp: In function 'int main()':
.\template.cpp:24:71: error: no matching function for call to 'MyClass<int, std::vector<int> >::call_me(<unresolved overloaded function type>, std::vector<int>::iterator, int)'
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4);
^
.\template.cpp:10:10: note: candidate: template<class F, class ... A> auto MyClass<T, C>::call_me(F, A ...) [with F = F; A = {A ...}; T = int; C = std::vector<int>]
auto call_me(F func, A... args) { // pass in the function we want to call
^~~~~~~
.\template.cpp:10:10: note: template argument deduction/substitution failed:
.\template.cpp:24:71: note: couldn't deduce template parameter 'F'
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4);
这与我在实际生产代码中遇到的错误相同,调用不带参数的可变参数函数来解包有效,但如果我提供的不止于此,我会收到相同的错误消息。这是我第一次真正尝试使用 Variadic 模板,因此我们将不胜感激任何建议和帮助。
这里的问题是 insert
是一个重载函数。编译器没有尝试解决您在模板参数推导中想要的重载,因为它无法知道。您必须将函数强制转换为您要使用的重载类型,以便为其指定类型。看起来像
using insert_func_t = std::vector<int>::iterator(std::vector<int>::*)(std::vector<int>::const_iterator, const int&);
test.call_me(static_cast<insert_func_t>(&std::vector<int>::insert), test.mContainer.begin(), 4);
一般来说是
static_cast<return_type(class_name::*)(function_parameters)>(&class_name::function_name)
另一种选择是稍微更改函数并使用 lambda 表达式来表达您想要完成的操作。看起来像
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A... args) { // pass in the function we want to call
return func(mContainer, args...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
int main() {
MyClass<int, std::vector<int> > test;;
test.call_me([](auto& container, auto... args){ container.insert(args...); }, test.mContainer.begin(), 4);
return 0;
}
基本上你不能获取未解析的重载函数的地址,因为编译器将无法选择正确的函数入口点地址。在正常的函数调用期间,编译器会解析重载函数,但是对于像您的模板或 std::bind() 这样的模板,这将不起作用,因为参数用于调用模板函数,而不是您要获取地址的函数。
您可以像这样手动解决过载问题:
using ftype = std::vector<int>::iterator(std::vector<int>::*)
(std::vector<int>::const_iterator, const std::vector<int>::value_type&);
test.call_me((ftype)(&std::vector<int>::insert), test.mContainer.begin(), 4); // works
做这种事情的时候处理函数对象比较容易。它将方法重载问题卸载给编译器。
Lambda 也可以工作(它们是函数对象):
#include <vector>
#include <iostream>
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A&&... args) -> decltype(auto)
{ // pass in the function we want to call
return func(mContainer, std::forward<A>(args)...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
/*
* It's often easier to deal in function objects
*/
struct insert
{
template<class Container, class...Args>
decltype(auto) operator()(Container& cont, Args&&...args) const
{
return cont.insert(std::forward<Args>(args)...);
}
};
struct size
{
template<class Container, class...Args>
decltype(auto) operator()(Container& cont) const
{
return cont.size();
}
};
int main() {
MyClass<int, std::vector<int> > test;;
std::cout << test.call_me(size()) << std::endl; // works
test.call_me(insert(), test.mContainer.begin(), 4); // doesn't work
// or lambdas
auto insert2 = [](auto& container, auto&&...args) -> decltype(auto)
{
return container.insert(std::forward<decltype(args)>(args)...);
};
test.call_me(insert2, test.mContainer.begin(), 5);
return 0;
}