我有一个模板,其模板参数代表一个功能。在模板中调用该函数,并且应该存储函数的结果,如下所示:
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;
}
答案 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 );