C ++为什么SFINAE仅使用类模板参数会失败? [英] C++ why does SFINAE fail with only a class template parameter?

查看:103
本文介绍了C ++为什么SFINAE仅使用类模板参数会失败?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用此答案样式的SFINAE,以便通过使用适当的方法来调用通用矢量对象成员函数。例如,以下代码首先调用 operator [](int)const ,如果不存在,则调用 operator()(int)const

I'm using SFINAE in the style of this answer in order to call a generic vector object by using an appropriate member function. For example, the following code calls operator[](int) const first, and if that doesn't exist then operator()(int) const:

template<int I> struct rank : rank<I-1> { static_assert(I > 0, ""); };
template<> struct rank<0> {};

template<typename VectorType>
struct VectorWrapper
{
    auto get(int i) const
    {
        return get(v, i, rank<5>());
    }

    template<typename V, typename = std::enable_if_t<has_bracket_operator<const V>::value> >
    auto get(V const& v, int i, rank<2>) const
    {
        return v[i];
    }

    template<typename V, typename = std::enable_if_t<has_parenthesis_operator<const V>::value> >
    auto get(V const& v, int i, rank<1>) const
    {
        return v(i);
    }

    VectorType v;
};

使用 has_bracket_operator has_parenthesis_operator 特征已按照此线程,整个编译并似乎可以正常工作

With the has_bracket_operator and has_parenthesis_operator traits set up as suggested in this thread, the whole compiles and seems to work.

但是,从一开始就没有必要将成员向量传递给重载的类模板,因此我尝试在不传递的情况下进行设置。为此,我将模板参数 V 替换为用于设置类模板的 VectorType 参数:

However, passing the member vector to the overloaded class templates seems unnecessary from the first, so I tried to set up the same without passing it. For this, I replaced the template parameter V with the VectorType parameter used to set up the class template:

    template<typename = std::enable_if_t<has_bracket_operator<VectorType>::value> >
    auto get(int i, rank<2>) const
    {
        return v[i];
    }

    template<typename = std::enable_if_t<has_parenthesis_operator<VectorType>::value> >
    auto get(int i, rank<1>) const
    {
        return v(i);
    }

现在,但是编译失败(在gcc 5.1.0中)出现以下错误消息:

Now, however, the compilation fails (in gcc 5.1.0) with the following error message:

/usr/local/include/c++/5.1.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = has_parenthesis_operator<std::vector<int> >::value; _Tp = void]':
main.cpp:46:10:   required from 'struct VectorWrapper<std::vector<int> >'
main.cpp:59:38:   required from here
/usr/local/include/c++/5.1.0/type_traits:2388:61: error: no type named 'type' in 'struct std::enable_if<false, void>'
     using enable_if_t = typename enable_if<_Cond, _Tp>::type;

演示

问题:


  • 此编译错误的原因是什么?

  • 除了第一个代码块以外,是否还有其他适当的解决方法? (也就是说,它保留了通常的编码样式-无需传递成员。)

推荐答案

SFINAE来自[temp.deduct] / 8,重点是我:

SFINAE comes to us from [temp.deduct]/8, emphasis mine:


如果替换导致类型或表达式无效,类型推导失败。无效的类型或表达式是
,如果使用替换的参数编写的话,它将格式错误,并且需要诊断。 [注意:
如果不需要诊断,则程序仍然格式错误。访问检查是替换
过程的一部分。 —end note] 仅在函数类型的直接上下文中无效的类型和表达式,以及其模板参数类型的
会导致推论失败。

If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed, with a diagnostic required, if written using the substituted arguments. [ Note: If no diagnostic is required, the program is still ill-formed. Access checking is done as part of the substitution process. —end note ] Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.

直接上下文是模板声明中的内容。在您的第一个示例中:

The immediate context is what's in the template declaration. In your initial example:

template<typename V, typename = std::enable_if_t<has_bracket_operator<const V>::value> >
auto get(V const& v, int i, rank<2>) const

V 是即时上下文,因此 enable_if 的替换失败只是推论失败。

V is in the immediate context, so a substitution failure on the enable_if is just a deduction failure.

但是,在第二个示例中:

However, in your second example:

template<typename = std::enable_if_t<has_bracket_operator<VectorType>::value> >
auto get(int i, rank<2>) const

VectorType 不在 get 的直接上下文中,因此此处的失败不是推论失败,而是硬错误。

VectorType is not in the immediate context of get, so a failure here would not be a deduction failure, it would be a hard error.

除非 VectorType 恰好具有所有这些运算符。

Unless VectorType happens to have all of these operators.

解决任何模板问题的方法是仅添加更多模板。在这种情况下,通过引入另一种类型来强制 VectorType 处于直接上下文中:

The solution to any template problem is to just add more template. In this case, force VectorType to be in the immediate context by introducing another type:

template<typename T=VectorType, typename = std::enable_if_t<has_bracket_operator<T>::value> >
auto get(int i, rank<2>) const

并调用 get<>()

这篇关于C ++为什么SFINAE仅使用类模板参数会失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆