Home > Software design >  Validity of C 20 concept
Validity of C 20 concept

Time:07-31

I am learning about C 20 concepts and I came across the following example that I don't know if it is well-formed(according to the standard) or not. The program is accepted by all compilers: Demo.

Basically, I want to know if this is the correct usage of concepts.

//define Element so that you can use it in vector require clause
template<typename T> bool constexpr Element(){
    if constexpr(std::is_same_v<T, int>)
    {
        return true;
    }
    else 
    {
        return false;
    }
};

template<typename T>        // for all types T
    requires (Element<T>())   // such that T is an Element
class vector {
        //...
};
int main()
{
    vector<int> v;
    
}

My question is that is this well-formed or is it ill-formed NDR. If there is anything wrong then how can we correct it here.

CodePudding user response:

There is no "C concept" in this code, as evidenced by the lack of the use of the concept keyword. You are using a template definition constrained by a requires clause, but that requires clause doesn't use an actual concept.

As for the validity of the code, it is legal C . Though it's also really bad C . Your use of if constexpr over-complicates what could just be return std::is_same_v<T, int>;. Which means that your Element function could be an Element concept rather than a function call: template<typename T> concept Element = std::is_same_v<T, int>;. And since C 20 has the std::same_as concept, you don't even need that. You should always use a standard library concept if one will fit.

CodePudding user response:

Yes, but no! It is well-formed because you are using type traits, which are compile-time boolean values, which are interchangeable with actual concepts and can be part of concept definitions.

At the same time, real concepts support a richer definition and usage syntax than booleans. For example, they can appear in template and function argument lists. Something like the following, although still a bit contrived, would make more sense to me:

#include <concepts>

template<std::integral T>
T constexpr foo_it(T value)
{
    if constexpr(std::same_as<T, int>) {
        // Do something specific for int values
    } else {
        // Generic function body for other integers
    }
    return value;
}

template<std::integral T> 
class vector {
        //...
};

int main()
{
    vector<int> v; // OK
    vector<double> w; // error: double is not integral
}

Your vector class example is odd in the sense that, if you were to design a vector only for integers, it would not need to be a template.

Apart from the usual learning materials, I've found it quite helpful to listen to Bjarne Stroustrup himself on this topic. Here is a short excerpt where he explains it to an interviewer.

  • Related