模板类的可变成员函数
Variadic member function of template class
我正面临一个问题,我正试图创建一个具有特定类型参数包的可变成员函数。
template <typename T>
struct A
{
using result_type = T;
T operator()(T a, T b)
{
return a+b;
}
};
template <typename Functor>
struct B
{
using T = typename Functor::result_type;
T operator()(Functor &&f, T... args)
{
return f(args...);
}
};
预期的工作方式如下:
A<int> a;
B<A<int>> b;
int result = b(a, 2, 3); // should return 5
但是我得到以下错误:
error: type 'T' (aka 'typename Functor::result_type') of function parameter pack does not contain any unexpanded parameter packs
T operator()(Functor &&f, T... args)
~^~~~~~~~
error: pack expansion does not contain any unexpanded parameter packs
return f(args...);
~~~~^
实现预期功能的正确方法是什么?
参数包只能在function是函数模板时使用。
从http://en.cppreference.com/w/cpp/language/parameter_pack:
模板形参包是一个接受零个或多个模板实参(非类型、类型或模板)的模板形参。函数形参包是接受零个或多个函数实参的函数形参。
至少有一个形参包的模板称为可变形参模板。
template <typename ... Args>
T operator()(Functor&& f, Args... args)
{
return f(args...);
}
同样,在上面的函数中使用&&
只有在它是模板形参时才有意义。当在实参上使用&&
而类型不是模板形参时,不能使用:
A<int> a;
B<A<int>> b;
int r = b(a, 2, 3);
但是,您可以使用
int r = b(std::move(a), 2, 3);
自己选吧。保持参数类型不变,使用std::move(a)
或将函数更改为使用简单引用
template <typename ... Args>
T operator()(Functor& f, Args... args)
{
return f(args...);
}
使用和
int r = b(a, 2, 3);
你可以使用一个辅助类来确保所有的参数都是正确的类型。
template<typename ... Args> struct IsSame : public std::false_type {};
template<typename T> struct IsSame<T> : public std::true_type {};
template<typename T, typename ... Args> struct IsSame<T, T, Args...> : public std::true_type
{
static const bool value = IsSame<T, Args ...>::value;
};
和使用:
template <typename ... Args>
T operator()(Functor&& f, Args... args)
{
static_assert(IsSame<T, Args...>::value, "Invalid argument type");
return f(args...);
}
,
A<int> a;
B<A<int>> b;
int r = b(std::move(a), 2, 3);
仍然有效但是
r = b(std::move(a), 2, 3.0);
失败。
我不知道在你的情况下是否需要严格的参数类型。如果你需要,你有办法的。
一个想法是使用std::initializer_list
代替,它将强制使用相同的类型(当然,您可能可以通过可变变量模板和一些聪明的使用std::is_same
来解决这个问题,以强制可变变量模板的所有参数使用相同的类型):
#include <algorithm>
#include <initializer_list>
#include <utility>
#include <iostream>
template <typename T>
struct A
{
using result_type = T;
T operator()(std::initializer_list<result_type> const& li)
{
return std::accumulate(std::begin(li), std::end(li), 0.);
}
};
template <typename Functor>
struct B
{
using T = typename Functor::result_type;
T operator()(Functor &&f, std::initializer_list<T> args)
{
return f(args);
}
};
int main()
{
A<int> functor;
B<decltype(functor)> test;
std::cout << test(std::move(functor), {1, 2, 3}); // displays 6
}
Live on Coliru
可以做一些SFINAE的技巧,比如:
struct Foo {};
template<class T, class...>
struct all_same : std::true_type
{};
template<class T, class U, class... SS>
struct all_same<T, U, SS...>
: std::integral_constant<bool, std::is_same<T,U>{} && all_same<T, SS...>{}>
{};
,
template <typename Functor>
struct B
{
using T = typename Functor::result_type;
template<typename ...Args>
T operator()(Functor&& f, Args... args)
{
static_assert(all_same<T, Args...>{}, "all not same types");
return f(args...);
}
};
Demo Here
您应该使用参数包。另外,为什么要传递一个右值引用呢?
template <typename Functor>
struct B
{
using T = typename Functor::result_type;
template<typename ...Args>
T operator()(Functor f, Args... args)
{
return f(args...);
}
};
编辑:如果你想验证所有的参数都是T类型,你可以声明一个验证结构体:
template <typename T, typename ...Pack>
struct verify_params {};
template <typename T>
struct verify_params<T> {
using val=void;
};
template <typename T, typename ...Pack>
struct verify_params<T,T,Pack...> {
using val=typename verify_params<T,Pack...>::val;
};
然后,你可以添加像(typename verify_params<T,Args...>::val)0;
这样的行到你的函数。
相关文章:
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 将公共但非静态的成员函数与ALGLIB集成
- 使用指向成员的指针将成员函数作为参数传递
- 将重载的成员函数传递给函数模板
- 我不小心调用了一个没有自己类对象的成员函数.但这是怎么回事呢
- 如何在C++中使用非静态成员函数作为回调函数
- C++错误C2600:无法定义编译器生成的特殊成员函数(必须首先在类中声明)
- 关联容器的下界复杂性:成员函数与非成员函数
- 在 C++ 中用派生类型重写成员函数
- 链表的泛型函数remove()与成员函数remove)
- 如何将lambda作为模板类的成员函数参数
- constexpr构造函数需要常量成员函数时出现问题
- 将自由函数绑定为类成员函数
- 区分非成员函数和头文件中的成员函数
- 如何从子成员函数修改父公共成员变量
- 保留对其他类的成员函数的引用
- 在运算符重载定义中使用成员函数(const错误)
- 内联如何影响模块接口中的成员函数
- 将成员函数指针作为参数传递给模板方法