2017-02-14 13 views
1

この小さな例では、2番目のパラメータのテンプレート引数を自動的に推論するようにコンパイラを設定しようとしています。これは機能しますが、私が望むように簡潔ではありません。std :: functionメンバ属性のテンプレート引数減算

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

エラーは、私はより簡潔な構文で動作するようにBのための関数の宣言にしなければならない何

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

です。

答えて

1

を、あなたは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で実装できます。関数、関数オブジェクト、およびメンバへのポインタの両方に適切な処理を行います。これは基本的に必要なものです。

+0

私は起動について知らなかった。 MSVC15でも動作するようです。 Thanks – Ronnie

+1

C++ 11のkludgeは 'std :: ref(attr)(s)'です。 –

+0

@ T.C。それだけで私は悲しいです。私は指針 - メンバー提案を書き直し、それを再提出する必要があります。私は本当に 'attr(s) 'を書いています。 – Barry

0

Bがより簡潔な構文で機能するためには、関数宣言に対して何をすればよいですか。

まず第一に、あなたが同じテンプレートidentificator使用する必要があります。attrを起動するか、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; 
} 
関連する問題