Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the concept in template template argument not verified?

C++20 allows the program to specify concept for template template argument. For example,

#include <concepts>

template <typename T> concept Char = std::same_as<T, char>;
template <typename> struct S {};
template <template <Char U> typename T, typename U> T<U> foo() { return {}; }

int main() { foo<S, int>(); }

the first template argument of the function foo is expected to be a single argument template.

The concept Char is defined to be true only the type char, so an attempt to satisfy it for int shall fail. Still above program is accepted by all compilers: https://gcc.godbolt.org/z/PaeETh6GP

Could you please explain, why the concept in template template argument can be specified, but it will be still ignored?

like image 490
Fedor Avatar asked Aug 02 '21 13:08

Fedor


People also ask

Why do we use :: template template parameter?

8. Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones.

What are template arguments enlist types of template arguments?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

Which is a correct example of template parameters?

For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.

What is a non type template parameter?

A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument. A non-type parameter can be any of the following types: An integral type. An enumeration type. A pointer or reference to a class object.


1 Answers

A template (actual) argument matches a template (formal) parameter if the latter is at least as specialised as the former.

template <Char> typename T is more specialised than template <typename> struct S. Roughly speaking, template <Char> accepts a subset of what template <typename> accepts (the exact definition of what "at least as specialised" actually means is rather involved, but this is a zeroth approximation).

This means that the actual argument can be used in all contexts where the formal parameter can be used. That is, for any type K for which T<K> is valid, S<K> is also valid (because S<K> is valid for any K).

So it is OK to substitute S for T.

If you do it the other way around:

template<typename T> concept Any = true; 
template<typename T> concept Char = Any<T> && std::same_as<T, char>;

template<template<Any> class T> void foo();
          
template<Char> struct S { };
          
int main()  
{           
    foo<S>(); 
}

then this is ill-formed, because (roughly) you can say T<int> but not S<int>. So S is not a valid substitute for T.

Notes:

  1. Why would we need this always-true concept Any? What's wrong with simply saying template <template <typename> typename>? Well, that's because of a special rule: if the parameter is not constrained at all, constraints of the argument are ignored, everything goes.
  2. Why write Any<T> && std::same_as<T, char>;? To illustrate a point. The actual rules do not evaluate the boolean values of constraints, but compare constraints as formulae where atomic constraints serve as variables, see here. So the formal reason is that S has a conjunction of a strictly larger (inclusion-wise) set of atomic constraints than T. If S had the same or a strictly smaller set, it would be well-formed. If two sets are not ordered by inclusion, then neither template is more specialised, and there is no match.
like image 177
n. 1.8e9-where's-my-share m. Avatar answered Sep 20 '22 08:09

n. 1.8e9-where's-my-share m.