Strange error with a templated operator overload

不打扰是莪最后的温柔 提交于 2019-11-29 13:38:44

Clang is right: operator overloading requires at least one class or enum type parameter, otherwise the program is ill-formed (13.5/1). To see why this error even appears, we have to parse some more Standard legalese.

Recall the Holy Trinity of Name Lookup, Argument Deduction and Overload Resolution. The first step finds two overloaded operator>. The second step deduces template arguments for each version. You might think that the second overload would fall victim to the SFINAE rule (14.8.2), so that only the first survives to the third step. However, there is no substition failure (as in e.g. a missing nested typedef), but an illegal construct (see the earlier mentioned 13.5/1). That itself renders the program ill-formed (14.3/6)

6 If the use of a template-argument gives rise to an ill-formed construct in the instantiation of a template specialization, the program is ill-formed.

In 14.8.3 it is mentioned that this check on the deduced arguments happens before overload resolution, so your preferred operator has no chance of being selected.

As a C++03 work-around, you could define two friend non-template operator> inside your Var<T> class template. These would be injected into the surrounding (global, in this example) namespace as non-template functions with one class type parameter, so the above error should not occur.

I must admit, I don't really know why clang complains here, it looks like a bug (of the compiler). Btw, clang 3.3 also exhibits the problem.

You can suppress it using SFINAE:

template<typename L>
typename std::enable_if<std::is_class<L>::value || std::is_enum<L>::value,
                        Greater<L, Const<int>>>::type
operator > (L lhs, int rhs) { 
    return Greater<L, Const<int> >(lhs, Const<int>(rhs));
}

template<typename R>
typename std::enable_if<std::is_class<R>::value || std::is_enum<R>::value,
                        Greater<Const<int>,R>>::type
operator > (int lhs, R rhs) { 
    return Greater<Const<int>, R>(Const<int>(lhs), rhs);
}

This looks like a bug in g++ and VS to me. In your example, your type R is int (because the right-hand operand is int). This then makes the signature of the function Greater<Const<int>, R> operator > (int lhs, int rhs) which is the same (parameter) signature as the builtin operator< for ints. Note that it has to consider both templates (and attempt to deduce types separately for each) when deciding which operator> to use: It can't just look at one of them and decide to ignore the other one.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!