缓存功能结果包括可能无效

时间:2015-12-25 17:54:36

标签: c++ templates c++14 template-meta-programming

我有一个模板,其模板参数代表一个功能。在模板中调用该函数,并且应该存储函数的结果,如下所示:

template <class F>
class C {
   F f;
   /* type see below */ cached;

   // ... somewhere ...
       cached = f();
};

我想稍后检索存储的值。现在,即使f返回void,该模板也可以正常工作。由于我无法生成void类型的变量,因此缓存的值应为void_placeholder_t类型。因此,我的课程应如下所示:

template <class F>
class C {
   F f;
   result_after_void_replacement_t<F()> cached;

   // ... somewhere ...
       cached = invoke_and_replace_void (f);
};

现在我整个下午都在解决这个问题,并提出了以下解决方案。老实说,我怀疑这个问题并不常见 - 所以没有一个标准的解决方案吗?

[抱歉,冗长。最后给出的例子。]

#include <iostream>
#include <typeinfo>
#include <functional>

struct void_placeholder_t {};

// dummy type, since we do not want to overload comma for void_placeholder_t
struct void_replacer { };

// overload comma to return either t oder void_replacer {}
// (uses that if first argument is void, overload is not called)
template <class T>
constexpr decltype(auto) operator , (T && t, void_replacer) {
    return std::forward<T> (t);
}

//
// replace_void
// helper transforming a void_replacer into a void_placeholder_t
template <class T>
constexpr decltype(auto) replace_void (T && t) {
    return std::forward<T> (t);
}

constexpr void_placeholder_t replace_void (void_replacer) {
    return void_placeholder_t {};
}

//
// remove_rvalue_reference
//
template<class T> struct remove_rvalue_reference { using type = T; };
template<class T> struct remove_rvalue_reference<T &&> { using type = T; };
template <class T> using remove_rvalue_reference_t
    = typename remove_rvalue_reference<T>::type;

//
// result_after_void_replacement, result_after_void_replacement_t
//
template <class S> struct result_after_void_replacement;
template <class F, class ... Args>
struct result_after_void_replacement <F (Args ...)> {
    using type
        = remove_rvalue_reference_t < decltype (
            replace_void(
            ( std::declval<F> () (std::declval<Args> () ...),
            void_replacer {} ) )
        ) >;
};

template <class S>
using result_after_void_replacement_t = typename 
    result_after_void_replacement<S>::type;

//
// invoke_and_replace_void
//
template <class F, class ... Args>
constexpr result_after_void_replacement_t<F && (Args &&...)>
invoke_and_replace_void (F && f, Args && ... args)
{
    return replace_void(
    ( std::forward<F> (f) (std::forward<Args> (args) ...),
    void_replacer {} ) );
}

// example

void f(double) { }
double g(double d) { return d + 11.0; }

int main() {
    // conversion, without invoke_and_replace_void
    auto xf = replace_void ( (f(42.0), void_replacer {}) );
    std::cout << typeid(xf).name () << std::endl;
    auto xg = replace_void ( (g(42.0), void_replacer {}) );
    std::cout << typeid(xg).name () << " " << xg << std::endl;

    // conversion, with invoke_and_replace_void and no type deduction
    using F = void (double);
    result_after_void_replacement_t<F& (double)> zf = 
        invoke_and_replace_void (f, 42.0);
    std::cout << typeid(zf).name () << std::endl;

    using G = double (double);
    result_after_void_replacement_t<G& (double)> zg = 
        invoke_and_replace_void (g, 42.0);
    std::cout << typeid(zg).name () << " " << zg << std::endl;
    return 0;
}

3 个答案:

答案 0 :(得分:3)

这应该适合您的情况

template <class F, bool>
class C_helper{
public:
   F f;
   /* type see below */ cached;

   // ... somewhere ...
       cached = f();
};
template <class F>
class C_helper<F, true> {
public:
   F f;

   // ... somewhere ...
       f();
};

template <class F>
class C: public C_helper<F, std::is_void<std::result_of<F()>>::value> {
};

答案 1 :(得分:3)

没有标准解决方案,因为在&#34; C ++标准中的东西&#34;。有人试图支持"Regular Void",这在2015年10月的会议上并不受进化工作组的青睐。

通常的方法是处理函数对象可能返回void的情况,并且将使用特化处理该值。特别是当所讨论的功能模板相对复杂且常见部分不能轻易考虑时,不幸的是这种方法很烦人。

答案 2 :(得分:1)

这很好用:

template <typename Fn, typename RET, typename... Args >
struct Cache
{
    Cache( Fn f ) : _fn(f) {}
    const RET& operator()(Args ...args)
    {
        _cache = _fn( std::forward<Args>( args ) ... );
        return _cache;
    }
    Fn _fn;
    RET _cache;
};

template <typename Fn, typename... Args >
struct Cache< Fn, void, Args...>
{
    Cache( Fn f ) : _fn(f) {}
    void operator()(Args ...args)
    {
        _fn( std::forward<Args>( args ) ... );
    }
    Fn _fn;
};

template <typename Fn, typename... Args >
using C = Cache< Fn, typename std::result_of< Fn( Args... ) >::type, Args... >;

void f(double) { }
double g(double d) { return d + 11.0; }


C<decltype(&g), double> cache_g(g);
double res = cache_g( 1.0 );

C<decltype(&f), double> cache_f(f);
cache_f( 2.0 );
相关问题