当我在使用decltype时调查boost::fusion::fused
函数包装器中的错误时出现此问题。问题似乎是,无效的decltype是编译错误,即使不会使用需要该模板的实例化,并且我也无法弄清楚如何解决该问题以创建通用函数包装器。
这是我对单参数包装程序的尝试:
#include <utility>
#include <type_traits>
template <class T>
typename std::add_rvalue_reference<T>::type declval();
template <class Fn, class Arg>
struct get_return_type
{
typedef decltype(declval<Fn>()(declval<Arg>())) type;
};
template <class Fn>
struct wrapper
{
explicit wrapper(Fn fn) : fn(fn) {}
Fn fn;
template <class Arg>
typename get_return_type<Fn,Arg&&>::type
operator()(Arg&& arg)
{
return fn(std::forward<Arg>(arg));
}
template <class Arg>
typename get_return_type<const Fn,Arg&&>::type
operator()(Arg&& arg)
{
return fn(std::forward<Arg>(arg));
}
};
问题是,这对于非const版本的参数不能转换为const版本的参数的情况不起作用。例如:
#include <iostream>
struct x {};
struct y {};
struct foo
{
void operator()(x) { std::cout << "void operator()(x)" << std::endl; }
void operator()(y) const { std::cout << "void operator()(y) const" << std::endl; }
};
int main()
{
wrapper<foo> b = wrapper<foo>(foo());
b(x()); // fail
}
在我看来,由
void operator()(y) const
引起的decltype表达式的失败应该只是由于SFINAE而导致该函数被删除。 最佳答案
这是在g++ 4.6.1上可以正常编译的代码:
#include <utility>
#include <type_traits>
#include <iostream>
template <class Fn, class Arg>
struct get_return_type
{
typedef decltype( std::declval<Fn>() ( std::declval<Arg>() ) ) type;
};
template <class Fn>
struct wrapper
{
explicit wrapper(Fn fn) : fn(fn) {}
Fn fn;
template <class Arg>
typename get_return_type<Fn,Arg&&>::type
operator()(Arg&& arg)
{
return fn(std::forward<Arg>(arg));
}
template <class Arg>
typename get_return_type< const Fn,Arg&&>::type
operator()(Arg&& arg) const
{
return fn(std::forward<Arg>(arg));
}
};
struct x {};
struct y {};
struct foo
{
x* operator()(x) { std::cout << "x* operator()(x)" << std::endl; return nullptr; }
x operator()(x) const { std::cout << "x operator()(x) const" << std::endl; return x(); }
y* operator()(y) { std::cout << "y* operator()(y)" << std::endl; return nullptr; }
y operator()(y) const { std::cout << "y operator()(y) const" << std::endl; return y(); }
};
template <class Fn>
void test_foo(Fn fn)
{
// make sure all operator() overloads are callable
const Fn& cfn = fn;
x* a = fn(x());
x b = cfn(x());
y* c = fn(y());
y d = cfn(y());
(void)a;(void)b;(void)c;(void)d;
}
int main()
{
test_foo(foo());
test_foo(wrapper<foo>(foo())); // fail
}
关于c++ - C++中的通用函数包装器可能吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10646469/