Equivalence of a template or functional equivalence of a template?

The C ++ standard [temp.over.link] explains that determining the equivalence of a function template should not include the "heroic efforts" of the compiler.

As an example, the C ++ standard offers the following:

// guaranteed to be the same template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+10>); // guaranteed to be different template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+11>); // ill-formed, no diagnostic required template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+1+2+3+4>); 

Is this rule also applicable to metaprogramming cases, as in the example below?

 template<class T> struct t_{ using type = T; }; //ill-formed or different? template<class T> T f(T); template<class T> typename t_<T>::type f(T); 
+4
source share
2 answers

Let's start with a simple case:

 template <typename T> using id = T; template<class T> T f(T); template<class T> id<T> f(T); 

This is clearly poorly formed for me, diagnostics are not required, for the corresponding rule . These two declarations are functionally equivalent, but not so that they simply rename the template parameters (and there are no dependent names to consider).


With a more complicated case:

 template <typename T> struct id_t { using type = T; }; template <typename T> using id = typename id_t<T>::type; template<class T> T f(T); template<class T> id<T> f(T); 

I think this is probably not poorly formed because they are not actually functionally equivalent. There may be id_t specializations, so the two declarations are really different, so these are actually different declarations.

+3
source

I think they are considered different in this scenario:

 template<class T> struct t_{ using type = T; }; //ill-formed or different? template<class T> T f(T); template<class T> typename t_<T>::type f(T); 

Because [temp.over.link] says ( emphasis mine )

To determine whether dependent names are equivalent, only the name itself is considered, and not the result of the name search in the template context .

Since T and typename t_<T>::type differ in naming, the compiler will accept these template declarations.

Now you can’t name them both, because the resulting template instances are functionally equivalent, which leads to ambiguity. Such a program is poorly formed, no diagnostics are required * (See @Barry for an excellent answer ).

MSVC 19.00.23506 , clang 6.0.0 and gcc 8.0.0 all seem to agree with me on this (none of them give diagnostics).

Note that the compiler allows you to declare these patterns until they call, while something like this will not compile, even if the patterns are not created:

 template<class U> typename t_<U>::type f(U){return {};} template<class T> typename t_<T>::type f(T){return {};} 

* "If the program contains declarations of function templates, functionally equivalent but not equivalent, the program is poorly formed, no diagnostic is required."

+2
source

Source: https://habr.com/ru/post/1273878/


All Articles