Это появилось, когда я искал ошибку в оболочке функции boost::fusion::fused
при использовании decltype. Похоже, проблема заключается в том, что недопустимый 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));
}
};
Проблема в том, что это не работает в случаях, когда аргументы неконстантной версии нельзя преобразовать в аргументы константной версии. Например:
#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
}
Мне кажется, что сбой выражения decltype, вызванный void operator()(y) const
, должен просто привести к удалению этой функции из-за SFINAE.
no match for call to (const foo)(x)
- person BЈовић   schedule 18.05.2012get_return_type<const Fn,Arg&&>::type
терпит неудачу и вместо того, чтобы быть удаленным из-за SFINAE, вызывает ошибку компиляции. - person Ayjay   schedule 18.05.2012