【发布时间】:2015-03-24 09:40:25
【问题描述】:
我想写一个wrapper 类(非常像一个代理)来聚合一个对象,并将成员函数调用转发给它。这在 C++11/14 中使用可变参数模板和decltype 是微不足道的。我的问题是包装对象可能支持也可能不支持的成员函数。
我想出了一个似乎可行的解决方案,但是它看起来非常笨拙,我正在寻找简化方法。特别是我担心这在编译时可能会非常昂贵(有 许多 函数要包装)。这种笨拙来自于需要指定函数的返回类型,而不需要 decltype 一些令人窒息的东西。
有人有更好的主意吗?
以下代码也可以使用live。
#include <iostream>
#include <utility>
/// Compute the result type of a member function call, or void if invalid.
#define RESULT_OF(Name) \
template <typename T> \
class result_impl_ ## Name \
{ \
public: \
/* Type made public to please Clang 3.7. */ \
template <typename C, typename... Args> \
static auto Type(void*) \
-> decltype(std::declval<C>().Name(std::declval<Args>()...)); \
\
template <typename, typename...> \
static void Type(...); \
\
template <typename... Args> \
using type = decltype(Type<T, Args...>(0)); \
}; \
\
template <typename T, typename... Args> \
using maybe_result_of_ ## Name \
= typename result_impl_ ## Name<T>::template type<Args...>
/// Forward to function Name, if is exists.
#define FORWARD(Name) \
template <typename... Args> \
auto Name(Args&&... args) \
-> maybe_result_of_ ## Name<Base, Args...> \
{ \
return base.Name(std::forward<Args>(args)...); \
}
#define DEFINE(Name) \
RESULT_OF(Name); \
FORWARD(Name)
template <typename Base>
struct wrapper
{
Base base;
DEFINE(foo);
DEFINE(bar);
};
#define PING() \
std::cerr << __PRETTY_FUNCTION__ << '\n'
struct foo_no_bar
{
void foo(int) const { PING(); }
int foo(double) const { PING(); return 1; }
int foo(double, double) const { PING(); return 1; }
};
struct foo_and_bar
{
void foo() const { PING(); }
void bar() { PING(); }
};
int main()
{
wrapper<foo_and_bar> f;
f.foo();
f.bar();
wrapper<foo_no_bar> b;
b.foo(1);
b.foo(1.0);
b.foo(1.0, 2.0);
}
【问题讨论】:
-
为什么不使用
decltype(auto)? -
@Jamboree 你能举个例子来说明你的意思和它是如何工作的吗?
-
@akim
auto遵循模板参数推导规则。decltype(auto)遵循 decltype 规则。 -
如果您在从包装器调用成员函数时使用
operator->而不是.表示法很舒服,那么实现起来非常简单。你会对这样的解决方案感兴趣吗? -
@remyabel 是的,确实,我知道这一点。但是
auto和decltype(auto)对 SFINAE 不友好,所以我看不出它是如何工作的。你有具体的例子吗?