成员函数指针作为模板参数的问题
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限定符,但同样的问题仍然存在。
我还想保持使用成员函数指针作为模板参数的设计,尽管通过使用非成员函数指针可以解决这个特殊问题。
感谢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';
}
最大的问题是你试图记住一个签名函数:
unsigned long calculate();
,但你调用记忆缓存的返回函数F::get(this)
与num - 1
或num - 2
。
换句话说:记忆依赖于"使用相同参数调用的函数产生相同的返回值"这一事实,但是你记忆的函数不接受任何参数(这本身没有错),但是你也不应该传递任何参数给它。
当前的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';
}
相关文章:
- C++复杂情况的比较器通过参数问题
- C++17 中的歧义错误(模板模板参数和默认参数问题)
- C 缺少模板参数问题
- C++ pcap_loop() 参数问题
- 带有指针作为参数问题的 C++ 函数
- C++ 奇怪的字符*参数问题(不兼容的类型)
- JNA 参数问题:内存访问无效
- Qt样式表和"一个参数"问题
- 默认参数问题 (c++)
- 具有可变模板的递归继承和继承参数问题
- 命令行参数问题
- OpenCV 决策树参数问题
- winapi GetProcessMemoryInfo 无效参数问题
- 参数问题?至少我认为是这样
- 构造函数参数问题C++
- c++教程参考参数问题
- c++多线程参数问题
- Clang Format多行函数声明参数问题
- 提升Python - 具有默认参数问题的重载函数
- VBA Excel DLL参数问题-第6个参数