Home Template equivalence or template functional equivalence?
Reply: 2

Template equivalence or template functional equivalence?

Oliv
1#
Oliv Published in 2017-12-06 16:18:04Z

In the C++ standard [temp.over.link], it is explained that the determination of function template equivalence should not involve "heroic efforts" of the compiler.

As an example, the C++ standard propose this:

// 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 applies to cases involving meta programming, 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);
Barry
2#
Barry Reply to 2017-12-06 16:53:16Z

Let's start with the simple case:

template <typename T> using id = T;

template<class T> T f(T);
template<class T> id<T> f(T);

This to me is clearly ill-formed, no diagnostic required, per the relevant rule. The two declarations are functionally equivalent, but not in a way that's simply renaming template parameters (and there aren't any dependent names to consider).


With the 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 ill-formed, because they aren't truly functionally equivalent. There could be specializations of id_t such that these two declarations are actually different - so these are actually different declarations.

AndyG
3#
AndyG Reply to 2017-12-06 16:59:18Z

I think that in this scenario they are considered different:

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)

For determining whether two dependent names are equivalent, only the name itself is considered, not the result of name lookup in the context of the template.

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

Now, you couldn't actually call either of them because the resulting template instantiations are functionally equivalent, resulting in ambiguity. This sort of program is ill-formed, no diagnostic required* (See @Barry's great answer).

MSVC 19.00.23506, clang 6.0.0, and gcc 8.0.0 all appear to agree with me on this (none of them issue a diagnostic).

Note that the compiler allows these templates to be declared, so long as they aren't called, whereas something like this won't compile even if the templates are not instantiated:

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

* "If a program contains declarations of function templates that are functionally equivalent but not equivalent, the program is ill-formed, no diagnostic required."

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.316914 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO