C++ 缓存函数结果,可能包括void
我有一个模板,其模板参数表示函数。该函数在模板中调用,函数的结果应存储,如下所示:C++ 缓存函数结果,可能包括void,c++,templates,c++14,template-meta-programming,C++,Templates,C++14,Template Meta Programming,我有一个模板,其模板参数表示函数。该函数在模板中调用,函数的结果应存储,如下所示: template <class F> class C { F f; /* type see below */ cached; // ... somewhere ... cached = f(); }; 现在我在这个问题上花了整个下午的时间,并提出了以下解决方案。老实说,我怀疑这个问题是不常见的,所以没有一个标准的解决方案吗 [抱歉,太长了。最后给出了示例。] #in
template <class F>
class C {
F f;
/* type see below */ cached;
// ... somewhere ...
cached = 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;
}
#包括
#包括
#包括
结构void_占位符{};
//虚拟类型,因为我们不希望为void\u占位符\u t重载逗号
结构void_replacer{};
//重载逗号以返回命令void_replacer{}
//(如果第一个参数为void,则不调用重载)
模板
constexpr decltype(自动)运算符,(T&T,void\u replacer){
返回std::向前(t);
}
//
//替换无效
//将空\u替换符转换为空\u占位符\u t的帮助程序
模板
constexpr decltype(自动)替换\u void(T&&T){
返回std::向前(t);
}
constexpr void\u占位符\u t replace\u void(void\u replacer){
返回void_占位符_t{};
}
//
//删除右值引用
//
模板结构删除\u右值\u引用{using type=T;};
模板结构删除\u右值\u引用{using type=T;};
使用删除\u右值\u引用\u t的模板
=typename remove\u rvalue\u reference::type;
//
//无效替换后的结果,无效替换后的结果
//
替换后的模板结构结果;
模板
替换后的结构结果{
使用类型
=删除\u右值\u引用\u t;
};
模板
在\u void\u replacement\u t=typename之后使用result\u
替换后的结果::类型;
//
//调用并替换无效
//
模板
无效替换后的constexpr结果
调用和替换void(F&&F,Args&&…Args)
{
退换货无效(
(标准::转发(f)(标准::转发(args)…),
void_replacer{});
}
//范例
空f(双){}
双g(双d){返回d+11.0;}
int main(){
//转换,无需调用和替换
autoxf=replace_void((f(42.0),void_replacer{});
std::cout这应该适用于您的情况
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> {
};
模板
类C_助手{
公众:
F;
/*键入以下内容*/cached;
//……某处。。。
cached=f();
};
模板
类C_助手{
公众:
F;
//……某处。。。
f();
};
模板
C类:公共C_助手{
};
这很好用:
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 );
模板
结构缓存
{
缓存(Fn-f):\u-Fn(f){}
常量RET&运算符()(Args…Args)
{
_缓存=_fn(std::forward(args)…);
返回缓存;
}
Fn_Fn;
重新缓存;
};
模板
结构缓存
{
缓存(Fn-f):\u-Fn(f){}
void运算符()(Args…Args)
{
_fn(标准:正向(参数)…);
}
Fn_Fn;
};
模板
使用C=Cache::type,Args…>;
空f(双){}
双g(双d){返回d+11.0;}
C.g(g);
双分辨率=高速缓存(1.0);
C.f(f);
cache_f(2.0);
>P>没有“C++标准中的某个东西”的标准解决方案。在2015年10月的会议上有一个尝试支持进化论工作组不喜欢的。
通常的方法是处理函数对象可能返回void
,并且使用专门化处理值的情况。特别是当所讨论的函数模板相对复杂且公共部分不容易分解时,不幸的是,这种方法相当烦人。常用的方法是create类C
(或其部分)的专门化对于void
type,这将不会存储返回值。嗯,事实上,这可能更容易。一种潜在的黑客方法:typedef std::conditional\u t cached\u type;
和cached\u type f;
。如果f
返回voidf
将只是一个垃圾int
变量。f
应该只被调用吗一次?是的,我们可以假设。我在Bitbucket上放了一个改进的版本:。以防有人需要它。
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 );