简体   繁体   English

成员属性的 std::function 模板参数推导

[英]std::function template argument deduction for member attributes

With this small example, I'm trying to get the compiler to automatically deduce the template argument for the 2nd parameter.通过这个小例子,我试图让编译器自动推导出第二个参数的模板参数。 This works but is not as succinct as I would like.这有效,但没有我想要的那么简洁。

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);

Error is错误是

>..\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'

What do I have to do to the function declaration for B to work with the more concise syntax.我必须对 B 的函数声明做什么才能使用更简洁的语法。

To invoke attr , you need to use std::invoke :要调用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;
}

Or honestly:或者说实话:

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() is a C++17 function template, but you can implement it in C++11 per the reference attached. invoke()是一个 C++17 函数模板,但您可以根据所附参考在 C++11 中实现它。 It will do the right thing for both functions, function objects, and pointers to members - which is basically what you want.它将为函数、函数对象和指向成员的指针做正确的事情——这基本上是你想要的。

What do I have to do to the function declaration for B to work with the more concise syntax.我必须对 B 的函数声明做什么才能使用更简洁的语法。

First of all, you should use the same template identificator: or R or T首先,您应该使用相同的模板标识符:或RT

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM