[英]Variadic member function of template class
I'm facing an issue where I'm trying to create a variadic member function with paramater pack of a specific type. 我正面临一个问题,我正在尝试使用特定类型的参数包创建一个可变成员函数。
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...);
}
};
It is expected to work like: 它应该像以下一样工作:
A<int> a;
B<A<int>> b;
int result = b(a, 2, 3); // should return 5
However I get the following errors: 但是我收到以下错误:
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...);
~~~~^
What would be the proper way to achieve the expected functionality? 实现预期功能的正确方法是什么?
A parameter pack can be used only if function is a function template. 仅当函数是函数模板时,才能使用参数包。
From http://en.cppreference.com/w/cpp/language/parameter_pack : 来自http://en.cppreference.com/w/cpp/language/parameter_pack :
A template parameter pack is a template parameter that accepts zero or more template arguments (non-types, types, or templates).
模板参数包是一个模板参数,它接受零个或多个模板参数(非类型,类型或模板)。 A function parameter pack is a function parameter that accepts zero or more function arguments.
函数参数包是一个函数参数,它接受零个或多个函数参数。
A template with at least one parameter pack is called a variadic template.
具有至少一个参数包的模板称为可变参数模板。
template <typename ... Args>
T operator()(Functor&& f, Args... args)
{
return f(args...);
}
Also, use of &&
in the above function makes sense only if it is a template parameter. 另外,只有在模板参数中,在上述函数中使用
&&
才有意义。 When you use &&
on the argument without the type being a template parameter, you cannot use: 如果在参数上使用
&&
而类型不是模板参数,则不能使用:
A<int> a;
B<A<int>> b;
int r = b(a, 2, 3);
You may, however, use 但是,您可以使用
int r = b(std::move(a), 2, 3);
Make your pick. 随便挑选。 Keep the argument type as is and use
std::move(a)
or change the function to use a simple reference 保持参数类型不变并使用
std::move(a)
或更改函数以使用简单引用
template <typename ... Args>
T operator()(Functor& f, Args... args)
{
return f(args...);
}
and use 并使用
int r = b(a, 2, 3);
Update 更新
You can use a helper class to make sure that all the arguments are of the right type. 您可以使用帮助程序类来确保所有参数都是正确的类型。
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;
};
and use: 并使用:
template <typename ... Args>
T operator()(Functor&& f, Args... args)
{
static_assert(IsSame<T, Args...>::value, "Invalid argument type");
return f(args...);
}
With that, 接着就,随即,
A<int> a;
B<A<int>> b;
int r = b(std::move(a), 2, 3);
still works but 仍然有效
r = b(std::move(a), 2, 3.0);
fails. 失败。
I don't know whether being that strict with the argument types is called for in your case. 在你的情况下,我不知道对参数类型是否严格要求。 You have a way if you need to.
如果需要,你有办法。
One idea is to use a std::initializer_list
instead, which will force the same type (of course you can probably get around this with a variadic template and some clever use of std::is_same
to enforce the same type for all params of the variadic template): 一个想法是使用
std::initializer_list
,它将强制使用相同的类型(当然,您可以使用可变参数模板和一些巧妙使用std::is_same
来强制执行相同类型的所有params可变参数模板):
#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
}
Can do some SFINAE tricks like : 可以做一些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...>{}>
{};
Then, 然后,
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...);
}
};
You should use an argument pack. 你应该使用一个参数包。 Also, why do you try to pass a rvalue reference?
另外,为什么要尝试传递右值参考?
template <typename Functor>
struct B
{
using T = typename Functor::result_type;
template<typename ...Args>
T operator()(Functor f, Args... args)
{
return f(args...);
}
};
Edit: If you want to verify that all the arguments are of type T, you can declare a verifying struct: 编辑:如果要验证所有参数都是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;
};
And then, you can add a line like (typename verify_params<T,Args...>::val)0;
然后,您可以添加一行
(typename verify_params<T,Args...>::val)0;
to your function. 你的功能。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.