通过这个小例子,我试图让编译器自动推导出第二个参数的模板参数。这有效,但并不像我想的那样简洁。
struct Student {
AgeCategory age;
Income income;
bool is_student;
CreditRating credit_rating;
bool buys_computer;
};
// This works (A)
template<typename R>
auto calc_mean(const std::vector<Student> & in, std::function<R (Student const&)> attr)-> double
{
const auto mean = std::accumulate(std::begin(in), std::end(in), 0.0, [&attr](auto acc, const auto& val) {
// Call the attribute passed in
return acc += static_cast<double>(attr(val));
}) / static_cast<double>(in.size());
return mean;
}
// This doesn't work (B)
template<typename T>
auto calc_mean(const std::vector<Student> & in, T attr)-> double
{
const auto mean = std::accumulate(std::begin(in), std::end(in), 0.0, [&attr](auto acc, const auto& val) {
// Call the attribute passed in
return acc += static_cast<double>(attr(val));
}) / static_cast<double>(in.size());
return mean;
}
// Caller (A) - works but I have to explicitly state the attribute type
mean_stddev<AgeCategory>(buy, &Student::age);
// Caller (B) - what I'd like to be able to do and let compiler infer types
mean_stddev(buy, &Student::age);
错误是
>..\src\Main.cpp(16): error C2672: mean_stddev': no matching overloaded function found
1>..\src\Main.cpp(16): error C2784: 'std::tuple<double,double> mean_stddev(const std::vector<Student,std::allocator<_Ty>> &,T *)': could not deduce template argument for 'T *' from AgeCategory Student::* '
1> with
1> [
1> _Ty=Student
1> ]
1> c:\users\chowron\documents\development\projects\ml\src\Bayes.h(25): note: see declaration of mean_stddev'
我需要对B的函数声明做什么才能使用更简洁的语法。
答案 0 :(得分:1)
要调用attr
,您需要使用std::invoke
:
template <class R> // <-- NB: R, not T
double calc_mean(const std::vector<Student>& in, R attr)
{
const auto mean = std::accumulate(in.begin(), in.end(), 0.0, [&attr](auto acc, const auto& val) {
return acc + static_cast<double>(std::invoke(attr, val));
}) / static_cast<double>(in.size());
return mean;
}
老实说:
template <class R> // <-- NB: R, not T
double calc_mean(const std::vector<Student>& in, R attr)
{
double sum = 0.0;
for (auto const& s : in) {
sum += std::invoke(attr, s);
}
return sum / in.size();
}
invoke()
是一个C ++ 17函数模板,但您可以根据附带的引用在C ++ 11中实现它。它将为函数,函数对象和指向成员的指针做正确的事 - 这基本上就是你想要的。
答案 1 :(得分:0)
我需要对B的函数声明做什么才能使用更简洁的语法。
首先,您应该使用相同的模板识别器:或R
或T
template<typename T> // <--- use R here
auto calc_mean(const std::vector<Student> & in, R attr)-> double
{
const auto mean = std::accumulate(std::begin(in), std::end(in), 0.0, [&attr](auto acc, const auto& val) {
// Call the attribute passed in
return acc += static_cast<double>(attr(val));
}) / static_cast<double>(in.size());
return mean;
}