This happened when I was looking for an error in a function shell boost::fusion::fusedwhen using decltype. The problem is that the invalid decltype type is a compilation error, even if the required template instance is not used, and I cannot figure out how to get around this in order to create a common wrapper of functions.
Here is my one-argument wrapper attempt:
#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));
}
};
The problem is that this does not work for cases where the arguments of the non-envelope version are not converted to arguments for the const version. For instance:
#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());
}
It seems to me that the failure of the decltype expression caused by void operator()(y) constit should simply lead to the removal of this function due to SFINAE.
source
share