C++ Concepts Same and Assignable

血红的双手。 提交于 2019-12-02 01:28:15

After attacking the problem during the weekend, I think I have found the answer myself.

Eric Niebler and Casey Carter have a more refined definition of Same that supports multiple template arguments (not just two), but my definition should be basically right for the two-argument case.

When using -> Type, the purpose is that the expression in the brackets can be implicitly converted to Type. When using -> Same<Type>, the purpose is that the expression in the brackets is exactly Type. So they are different.

However, there is a gotcha. The constraint check is quite complicated, and even experts like Eric and Casey made a mistake and gave wrong definitions in N4569. Eric discussed the issue on GitHub:

https://github.com/ericniebler/stl2/issues/330

When used the way it was given in N4569, it means the expression should be able to be passed to an imagined function template like

template <typename U>
f(U)
requires Same<T&, U>()

This doesn't work—if the expression passed in is an lvalue of T, the deduced U is T instead of T&. The solution is use Same<T&>&& in Assignable. It will result in the following imagined function template:

template <typename U>
f(U&&)
requires Same<T&, U>()

Now everything is OK—if the expression passed in is an lvalue of T, U has to be deduced as T&.

Playing with concepts is a good practice for me, but I probably should find their code earlier. They have a complete set of concepts in the following GitHub repository:

https://github.com/CaseyCarter/cmcstl2

People interested in C++ concepts should look into it.

The issue with the definition of Same is a bit more subtle: the Ranges TS requires implementations to treat the constraint Same<T, U>() as equivalent to Same<U, T>(), i.e., recognize the symmetry of "T is the same type as U":

template <class T, class U>
requires Same<T, U>()
void foo(); // #1

template <class T, class U>
requires Same<U, T>()
void foo(); // redeclaration of #1

template <class T>
requires Same<int, T>()
void bar(); // #2

template <class T>
requires Same<T, int>()
void bar(); // redeclaration of #2

This equivalence can't be expressed in the language, since the rules for normalization of constraints recognize each of:

is_same_v<T, U>
is_same_v<U, T>
is_same_v<T, int>
is_same_v<int, T>

as distinct atomic constraints. This requires implementation of Same via a compiler intrinsic.

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