msvc2013 的 decltype 模板出错

error with decltype template with msvc2013

我正在尝试使用以下构造来检查是否存在基于我之前获得的 的成员函数:

template <typename T, class = double>
struct has_a : std::false_type {};

template <typename T>
struct has_a<T, decltype(std::declval<T>().a())> : std::true_type {};

这适用于 gcc 4.9.2,但无法使用 msvc2013 进行编译:

error C2228: left of '.a' must have class/struct/union type is 'add_rvalue_reference<_Ty>::type'

似乎(?)这是一个编译器错误,因为 declval 专门应该在未计算的 decltype 表达式 (see here) 中工作。有已知的解决方法吗?

MSVC 2013 的尾部 return 类型解析器似乎比表达式 SFINAE 系统更完整,如果检查器按以下方式重构 (following T.C's suggestion),它在 msvc2013 上都按预期工作和 gcc 4.9.2:

template <typename T>
struct has_a_impl
{
    template<typename U>
    static auto test(U* p) -> decltype(p->a()); // checks function existence
    template<typename U>
    static auto test(...) -> std::false_type;

    using type = typename std::is_floating_point<decltype(test<T>(0))>::type; // checks return type is some kind of floating point
};

template <typename T>
struct has_a : has_a_impl<T>::type {};

此语法的另一个好处是 return 类型检查可以使用任何 type_traits,因此您不必检查单一类型的 return 值(例如双)。