C# generics vs C++ templates - need a clarification about constraints

前端 未结 5 1010
萌比男神i
萌比男神i 2021-02-14 05:15

Duplicate

What are the differences between Generics in C# and Java… and Templates in C++?


Hi all,

I am experienced C++ p

5条回答
  •  终归单人心
    2021-02-14 05:52

    Well, in general, C++ templates and C# generics are similar - compared to Java generics which are completely different, but they have also large differences. Like in C#, there is runtime support by using reflection, getting an object describing the types used to instantiate a generics. C++ doesn't have reflection, and all it does with types is done at compile time.

    The biggest difference between C# generics and C++ templates indeed are that C# generics are better type checked. They are always constrained, in the sense that they don't allow operations that are not stated valid at the time of defining the generics. C#'s chief designer raised as a reason of that the added complexity it would have taken to have implied constraints. I'm not well versed with C#, so i can't talk further here. I'll talk about about how matters are in C++ and how they are going to be improved, so that people don't think C++'s stuff is all wrong.

    In C++, templates are not constrained. If you do an operation, at template definition time it is implied that the operation will succeed at instantiation time. It's not even required to a C++ compiler that the template is syntactically checked for validity. If it contains a syntax error, then that error has to be diagnosed at instantiation. Any diagnose before that is a pure goody of the implementation.

    Those implied constraint have shown to be easy for the template designer in the short term, because they don't have to care about stating the valid operations in their template interface. They put the burden on the user of their template - so the user has to make sure he fulfills all those requirements. Often it happens that the user tries seemingly valid operations but fails, with the compiler giving the user hundreds of lines of error messages about some invalid syntax or not found names. Because the compiler can't know what constraint in particular was violated in the first place, it lists all parts of code paths ever involved around the faulty place and all not even important details, and the user will have to crawl through the horrible error message text.

    That is a fundamental problem, which can be solved by just stating at the interface for a template or generics what properties a type parameter has to have. C#, as far as i know it, can constraint the parameter to implement an interface or inherit a base-class. It solves that on a type-level.

    The C++ committee has long seen there is need to fix these problems, and soon (next year, probably), C++ will have a way to state such explicit constraints too (see time-machine note below), as in the following case.

    template requires VariableType
    T f(T a, T b) {
        return a + b; 
    }
    

    The compiler signals an error at that point, because the expression as written is not marked valid by the requirements. This first helps the designer of the template to write more correct code, because the code is type-checked already to some degree (well to what is possible there). The programmer can now state that requirement:

    template requires VariableType && HasPlus
    T f(T a, T b) {
        return a + b; 
    }
    

    Now, it will compiler. The compiler, by seeing T appearing as the return type, automatically implied that T is copyable, because that use of T appears in the interface, rather than in the templates body. The other requirements were stated using requirement clauses. Now, the user will get a appropriate error message if he uses a type that doesn't have an op+ defined.

    C++1x decouples the requirements from the type. The above works for primitive types aswell as for classes. In this sense, they are more flexible, but quite a bit complex. The rules that state when and when requirements are satisfied are long... You can with the new rules say the following:

    template requires MyCuteType
    void f(T t) { *t = 10; }
    

    And then, call f with an int! That would work by just writing a concept map for MyCuteType that teaches the compiler how an int can be dereferenced. It will get quite handy in loops like this:

    for_each(0, 100, doSomething());
    

    Since the programmer can tell the compiler how an int can satisfy the concept of an input iterator, you could actually write such code in C++1x, if you only write the appropriate concept map, which really isn't all that difficult.

    Ok, enough with this. I hope i could show you that having templates constrained is not all that bad, but in fact better, because the relationship betweens types and the operations on them within the templates are now known by the compiler. And i haven't even written about axioms, which are another nice thing in C++1x' concepts. Remember that this is future stuff, it's not yet out, but it will approximately at 2010. Then we will have to wait for some compiler to implement that all :)


    UPDATE FROM "FUTURE"

    C++0x concepts were not accepted into the draft but have been voted out at late of 2009. Too bad! But perhaps we will see it again in the next C++ version? Let's all hope!

提交回复
热议问题