给定以下代码
struct data {
int velocity;
};
template <typename Data>
class Collector {
// ...
public:
void add(const Data& data) {}
template <typename T>
T average1(T Data::*field) const {
return T{}; // Some calculation here
}
template <T Data::*field>
T average2() const {
return T{}; // Some calculation here
}
};
void foo() {
Collector<data> collector;
// I have no problem handling the average by sending member as parameter
auto ok = collector.average1(&data::velocity);
// But compilation here fails
auto error = collector.average2<&data::velocity>();
}
我的意图是通过模板参数替换传递成员指针到函数,但不能同时匹配成员类型和成员,我可以做一些像
template <typename T, T Data::*field>
T average2() const {
return T{}; // Some calculation here
}
但是我必须调用as
auto error = collector.average2<int, &data::velocity>();
,这是一个但丑陋的,似乎没有必要的
你知道如何解决这个问题或者有更好的方法来收集这类数据吗?
Thanks in advance
在c++ 17中,您可以通过将value template参数扩展为auto
并在以后的行中解析T
(例如decltype()
)来使模板化版本工作。
#include <type_traits>
template <typename Data>
class Collector {
// ...
public:
template <auto field>
auto average2() const {
using T = decltype(std::declval<Data>().*field);
return T{}; // Some calculation here
}
};
void foo() {
Collector<data> collector;
// Works perfectly fine
auto error = collector.average2<&data::velocity>();
}
在c++ 20中,您可以通过将field
约束为Data
成员指针来使其更简洁。这将为您提供更严格的重载解析以及更好的错误消息。
#include <type_traits>
template<typename PtrT, typename ObjT>
concept MemberObjectPointerFor = std::is_member_object_pointer_v<PtrT> &&
requires(PtrT ptr, ObjT& obj) {
{ obj.*ptr };
};
template <typename Data>
class Collector {
// ...
public:
template <MemberObjectPointerFor<Data> auto field>
auto average2() const {
using T = decltype(std::declval<Data>().*field);
return T{}; // Some calculation here
}
};