簡體   English   中英

成員函數指針作為模板參數的問題

[英]Trouble with member function pointer as template argument

由於F類型不符合專業要求,因此下面的代碼中的注釋行將無法編譯。 有人可以解釋為什么嗎?

#include <memory>
#include <functional>
#include <map>
#include <tuple>

template <typename R, typename T, typename... Args>
std::function<R(Args...)> memoizeMemberFunction (R T::*f(Args...), const T* t) {
    auto cache = std::make_shared<std::map<std::tuple<const T*, Args...>, R>>();
    return ([f, cache](T* t, Args... args) {
        const std::tuple<const T*, Args...> tuple(t, args...);
        if (cache->find(tuple) == cache->end())
            (*cache)[tuple] = (t->*f)(args...);  // Insert 'tuple' as a new key in the map *cache.
        return (*cache)[tuple];
    });
}

template <typename Class, typename Fptr, Fptr> struct MemberFunctionMemoizer;

template <typename Class, typename R, typename... Args, R Class::*F(Args...)>
struct MemberFunctionMemoizer<Class, R (Class::*)(Args...) const, F> {
    static std::function<R(Class*, Args...)>& get (const Class* p) {
        static std::function<R (Args...)> memoizedF (memoizeMemberFunction(F, p)); 
        return memoizedF;
    }
};

struct FibonacciCalculator {
    unsigned long calculate(unsigned num) const {
        using F = MemberFunctionMemoizer<FibonacciCalculator,
            unsigned long (FibonacciCalculator::*)(unsigned) const, &FibonacciCalculator::calculate>;
//      return (num < 2) ? num : F::get(this)(num - 1) + F::get(this)(num - 2);
        // Won't compile because F does not meet the specialization.
    }
};

#include <iostream>

int main() {
    FibonacciCalculator fib;
    std::cout << fib.calculate(10) << '\n';
}

我在這里想念什么嗎? 如何獲得F來滿足專業化要求? 我嘗試從圖片中刪除const限定詞,但是仍然存在相同的問題。

我也想保持使用成員函數指針作為模板參數的設計,即使通過使用非成員函數指針可以解決此特定問題。

您遇到的最大問題是,您正試圖記住簽名功能:

unsigned long calculate();

但是您正在使用num - 1num - 2調用備忘錄緩存的返回函數F::get(this)

換句話說:記憶依賴於以下事實:“使用相同參數調用的函數會產生相同的返回值”,但是您要記憶的函數不帶任何參數(該參數本身沒有問題),但是您不應傳遞它任何參數。

您當前的FibonacciCalculator類無法使用記憶,因為它已被實現。

我已經實現了一種可能會實現您希望的效果; 它計算斐波那契數並記住成員函數調用...注意: memoizeMemberFunction()有一個額外的“噪聲”,但輸出表明它正在工作-您將在輸出中看到函數調用被使用兩次且僅被計算一旦。

#include <iostream>
#include <memory>
#include <functional>
#include <map>
#include <tuple>

template <typename R, typename T, typename... Args>
std::function<R(Args...)> memoizeMemberFunction (R (T::*f)(Args...), T* t) {
    auto cache = std::make_shared<std::map<std::tuple<T*, Args...>, R>>();
    return [f, t, cache](Args... args) {
        const std::tuple<T*, Args...> tuple(t, args...);
        if (cache->find(tuple) == cache->end()) {
            (*cache)[tuple] = (t->*f)(args...);  // Insert 'tuple' as a new key in the map *cache.
            std::cout << "Computed f(";
            int dummy[sizeof...(Args)] = { (std::cout << args << ", ", 0)... };
            std::cout << ") = " << (*cache)[tuple] << std::endl;
        }
        std::cout << "Using f(";
        int dummy[sizeof...(Args)] = { (std::cout << args << ", ", 0)... };
        std::cout << ") = " << (*cache)[tuple] << std::endl;
        return (*cache)[tuple];
    };
}

struct FibonacciCalculator {
    unsigned long num;
    unsigned long calculate(unsigned long n = (unsigned long)-1) {
        static auto memoizedF (memoizeMemberFunction(&FibonacciCalculator::calculate, this));
        if( n==(unsigned long)-1 )
            return memoizedF(num);
        return (n < 2) ? n : memoizedF(n-1) + memoizedF(n-2);
    }
};

int main() {
    FibonacciCalculator fib{ 10 };
    std::cout << fib.calculate() << '\n';
}

感謝dyp糾正了我在語法方面的艱苦努力,我完成了我打算要做的事情:

#include <memory>
#include <functional>
#include <map>
#include <tuple>

template <typename R, typename T, typename... Args>
std::function<R(Args...)> memoizeMemberFunction (R (T::*f)(Args...), T* t) {
    auto cache = std::make_shared<std::map<std::tuple<T*, Args...>, R>>();
    return ([f, cache, t](Args... args) {
        const std::tuple<T*, Args...> tuple(t, args...);
        if (cache->find(tuple) == cache->end())
            (*cache)[tuple] = (t->*f)(args...);  // Insert 'tuple' as a new key in the map *cache.
        return (*cache)[tuple];
    });
}

template <typename R, typename T, typename... Args>
std::function<R(Args...)> memoizeConstMemberFunction (R (T::*f)(Args...) const, const T* t) {
    auto cache = std::make_shared<std::map<std::tuple<const T*, Args...>, R>>();
    return ([f, cache, t](Args... args) {
        const std::tuple<const T*, Args...> tuple(t, args...);
        if (cache->find(tuple) == cache->end())
            (*cache)[tuple] = (t->*f)(args...);  // Insert 'tuple' as a new key in the map *cache.
        return (*cache)[tuple];
    });
}

template <typename Class, typename Fptr, Fptr> struct MemberFunctionMemoizer;
template <typename Class, typename Fptr, Fptr> struct ConstMemberFunctionMemoizer;

template <typename Class, typename R, typename... Args, R (Class::*F)(Args...) const>
struct ConstMemberFunctionMemoizer<Class, R (Class::*)(Args...) const, F> {
    static std::function<R(Args...)>& get (const Class* p) {
        static std::function<R (Args...)> memoizedF (memoizeConstMemberFunction(F, p)); 
        return memoizedF;
    }
};

template <typename Class, typename R, typename... Args, R (Class::*F)(Args...)>
struct MemberFunctionMemoizer<Class, R (Class::*)(Args...), F> {
    static std::function<R(Args...)>& get (Class* p) {
        static std::function<R (Args...)> memoizedF (memoizeMemberFunction(F, p)); 
        return memoizedF;
    }
};

// Testing
#include <iostream>
#include <vector>

struct FibonacciCalculator {
    std::vector<unsigned long> computed;
    unsigned long calculate (unsigned num) const {
        using F = ConstMemberFunctionMemoizer<FibonacciCalculator, unsigned long (FibonacciCalculator::*)(unsigned) const, &FibonacciCalculator::calculate>;  // 'decltype(&FibonacciCalculator::calculate)' can be used in place of 'unsigned long (FibonacciCalculator::*)(unsigned) const'.
        return (num < 2) ? num : F::get(this)(num - 1) + F::get(this)(num - 2);
    }
    unsigned long calculateAndStore (unsigned num) {
        using F = MemberFunctionMemoizer<FibonacciCalculator, unsigned long (FibonacciCalculator::*)(unsigned), &FibonacciCalculator::calculateAndStore>;  // 'decltype(&FibonacciCalculator::calculateAndStore)' can be used in place of 'unsigned long (FibonacciCalculator::*)(unsigned)'.
        const unsigned long result = (num < 2) ? num : F::get(this)(num - 1) + F::get(this)(num - 2);
        computed.push_back(result);
        return result;
    }
};

int main() {
    FibonacciCalculator fib;
    for (unsigned i = 1; i < 20; i++)
        std::cout << fib.calculate(i) << ' ';  // 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
    std::cout << '\n';

    for (unsigned i = 1; i < 20; i++)
        std::cout << fib.calculateAndStore(i) << ' ';  // 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
    std::cout << '\n';
    for (unsigned long x : fib.computed)
        std::cout << x << ' ';  // 1 1 0 1 1 2 2 3 3 5 5 8 8 13 13 21 21 34 34 55 55 89 89 144 144 233 233 377 377 610 610 987 987 1597 1597 2584 2584 4181
    std::cout << '\n';  
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM