简体   繁体   English

成员函数指针作为模板参数的问题

[英]Trouble with member function pointer as template argument

The commented-out line in the code below won't compile because type F does not meet the specialization. 由于F类型不符合专业要求,因此下面的代码中的注释行将无法编译。 Can someone explain why? 有人可以解释为什么吗?

#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';
}

Am I missing something here? 我在这里想念什么吗? How to get F to meet the specialization? 如何获得F来满足专业化要求? I tried removing the const qualifiers out of the picture, but the same problem persists. 我尝试从图片中删除const限定词,但是仍然存在相同的问题。

I also want to maintain the design of using a member function pointer as template argument, even though there is a solution to this particular problem by using a non-member function pointer. 我也想保持使用成员函数指针作为模板参数的设计,即使通过使用非成员函数指针可以解决此特定问题。

The biggest issue you have is the fact that you're trying to memoize a function of signature: 您遇到的最大问题是,您正试图记住签名功能:

unsigned long calculate();

but you're calling the memoization cache's returned function F::get(this) with num - 1 or num - 2 . 但是您正在使用num - 1num - 2调用备忘录缓存的返回函数F::get(this)

In other words: memoization relies on the fact that "function called with identical arguments yields identical return value" but the function you're memoizing doesn't take any parameters (nothing wrong with that in itself) but then you shouldn't pass it any parameters either. 换句话说:记忆依赖于以下事实:“使用相同参数调用的函数会产生相同的返回值”,但是您要记忆的函数不带任何参数(该参数本身没有问题),但是您不应传递它任何参数。

Your current FibonacciCalculator class cannot use memoization, as it is currently implemented. 您当前的FibonacciCalculator类无法使用记忆,因为它已被实现。

I have made an implementation that sort of might do what you hoped; 我已经实现了一种可能会实现您希望的效果; it computes Fibonacci numbers and it memoizes the memberfunction call ... Note: there's extra 'noise' in the memoizeMemberFunction() but that's output to show that it's working - you'll see in the output that function calls are used twice and computed only once. 它计算斐波那契数并记住成员函数调用...注意: 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';
}

Thanks to dyp for correcting my horrible struggle with syntax, I have accomplished what I set out to do: 感谢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