0

私にはうまく機能する関数があります:

template <typename __container, typename __callback = std::function <
    void (typename __container::value_type, typename __container::value_type)>
>
int reduce(__container &&container, __callback &&callback)
{
    auto current = container.begin();

    for (auto value : container)
        *current = callback(*current, value);

    return *current;
};


int result = functional::reduce(vector, [](const int current, const int next) -> int {
    return current + next;
});

std::cout << result; // 10

そして今、私は1つを統一するつもりです:

template <typename __container, typename __callback = std::function <
    void (typename __container::value_type, typename __container::value_type)>
>
auto reduce(__container &&container, __callback &&callback) ->
 decltype(__container::value_type);

ただし、次のエラーが発生します。

reduce.cpp:61:9: error: no matching function for call to 'reduce'
int i = reduce(vector, [](const int current, const int next) -> int {
        ^~~~~~~~~~~~~~~~~~
reduce.hpp:69:7: note: candidate template ignored: substitution failure [with __container = std::__1::list<int, std::__1::allocator<int>> &, __callback = <lambda at
      nott.cpp:61:36>]
        auto reduce(__container &&container, __callback &&callback) -> decltype(__container::value_type)
             ^
1 error generated.
make: *** [build] Error 1

ジェネリックリターンタイプを設定するにはどうすればよいですか?

アップデート:

template <typename __container, typename __callback>
auto reducef(const __container& input, __callback callback) ->
decltype(callback(std::declval<typename __container::value_type>(), std::declval<typename __container::value_type>()))
{
    decltype(
        callback(
            std::declval<typename __container::value_type>(),
            std::declval<typename __container::value_type>()
        )
    ) result{};

    return std::accumulate(input.begin(), input.end(), result, callback);
};
4

2 に答える 2

4

この署名は間違っています:

auto reduce(__container &&container, __callback &&callback) ->
 decltype(__container::value_type);

value_typeはタイプであり、あなたはそれをdecltypeします。これはのようなものdecltype(int)です。ただし、__container::value_typeコンパイラはそれが型であることを認識していないため、どちらも機能しませんvalue_type。を使用してこれを明示的にする必要がありますtypename

auto reduce(__container &&container, __callback &&callback) ->
 typename __container::value_type;

改善できることがさらにいくつかあります。コンパイラのフロント要素を変更して、それを減らします。私はあなたがこのようなことをしたいと思います:

auto current = *container.begin(); // added *

for (auto value : container)
    current = callback(*current, value); // removed *

return current; // removed *

さらに別のバグがあります。最初の値が2回減少します。

assert(!container.empty());
auto current = *container.begin();

for (auto it=container.begin()+1; it!=container.end(); ++it)
    current = callback(current, *it);

return current;

さらなる改善:範囲の代わりにイテレータを使用します。

template <typename Iter, typename Callback>
T reduce(Iter start, Iter end, Callback&& F)
{
    assert(start != end);
    auto current = *start;
    while (++start != end)
      current = callback(current, *it);
    return *current;
};

次の質問:なぜ空の範囲を受け入れないという制限があるのですか?そのための初期値を使用してください。

template <typename Iter, typename T, typename Callback>
T reduce(Iter start, Iter end, T init, Callback&& F)
{
    while (start != end)
      init = callback(init, *it++);
    return init;
};

そして、驚いたことに、これはまさにの定義ですstd::accumulate

于 2013-01-08T18:09:19.357 に答える
1

他の人が指摘しているように、あなたは必要ありませんdecltype。また、必要はありませんauto。コードをあなたが持っていたものにできるだけ近づけて(スタイルは目前の問題ではないので)、これが動作するバージョンです:

#include <iostream>
#include <vector>

template <typename Container, typename Callback>
typename Container::value_type reduce(Container &container, Callback &&cb) {
    auto current = container.begin();

    for (auto value : container)
        *current = cb(*current, value);

    return *current;
}

int main() {
    std::vector<int> v = {1, 2, 3};

    int result = reduce(v, [](const int current, const int next) -> int {
         return current + next;
    }); 

    std::cout << "result = " << result << std::endl;
}
于 2013-01-08T18:18:17.373 に答える