2015-10-11 140 views
0

下面代碼中的註釋行不會編譯,因爲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修飾符,但同樣的問題仍然存在。

我也想維護使用成員函數指針作爲模板參數的設計,即使通過使用非成員函數指針有解決此特定問題的方法。

+0

常量性。成員函數指針模板參數不是const限定的。另外,我認爲'R Class :: * F(Args ...)'不是指向成員函數的指針。 – dyp

+0

我試着調整const,包括使'calculate()'非const,並且仍然得到相同的問題。如何解決這個問題? – prestokeys

+0

我覺得'R Class :: * F(Args ...)'是一個函數,它返回一個指向成員的指針,即'auto F(Args ...) - > R Class :: *'。 OTOH,'R(Class :: * F)(Args ...)'是一個指向成員函數的指針,可以是const限定的。 – dyp

回答

0

你擁有的最大的問題是你想memoize的簽名的函數的事實:

unsigned long calculate(); 

,但你與num - 1num - 2調用記憶化高速緩存的返回功能F::get(this)

換句話說:memoization依賴於「使用相同參數調用的函數產生相同的返回值」這一事實,但是您正在記憶的函數不帶任何參數(本身沒有任何錯誤),但是您應該也不會傳遞任何參數。

您當前的FibonacciCalculator類無法使用memoization,因爲它目前已實施。

我已經實現了那種可能做你想做的事情;它計算斐波那契數字它記憶成員函數調用... 注意:在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'; 
} 
0

感謝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'; 
} 
相關問題