It is not how you think of them, rather what is possible to do with their expressiveness.
C# type checks imply a performance hit and are an implementation detail. Nothing prevents a C# compiler to choose another one. It has nothing to do with generics vs templates.
For example Modula-3 and Ada compilers use the same approach as C++ for code generation of their generics.
So where is that example of something that can only be written with C# generics, but not with C++ templates?
It is not the case of what can only be written, but what can be written and typechecked. C# generics offer much stronger type safety for library writers than C++ templates.
C++ templates are not type-checked. C# (and Java, and Scala and Haskell) generics are.
No, they are not. This code compiles fine, despite an obvious non-generic type-error. You may add whatever number of type traits, constexprs, etc there, and it will still compile fine as long as syntax is ok.
#include <string>
template <typename T>
void foo(const T& arg) {
int x = std::string("int expected");
}
$ g++ -c template.cpp
$ // see, no error
Templates are only syntax-checked. The type checker is not even executed on the non-generic code inside of templates. The type checker will be executed after the template is instantiated (expanded). At that point, generic types do not exist. There exist only concrete types.
Sure, you can type-check them for particular type arguments. But you can't type-check them generally at the generic level and you have absolutely no guarantee that your library code is free of type errors. Not a problem if the goal is to produce the final executable, but a big problem for a library writer, who doesn't control the inputs (in this case: the types provided by the user of the library).
And AFAIK C++17 concepts do not address this problem, really. I can constrain my input types with them, and the calling code will be forced to conform to them (and the compiler will present a nice error message if it doesn't), but there is still no checking on the other side - that is if the template implementation is correct assuming these constraints. I can publicly declare my code requires T.bar(), then shamelessly call T.baz() in the template implementation and the compiler will not catch it.
This is like a Python program. You don't know if it type-checks before you run it, but even if you run it once or twice and it was fine, that doesn't guarantee there are no type errors.
The code line int x = std::string("int expected"); has zero relation with any of the template arguments.
So a programmer error that doesn't have anything to do with the types provided for the template.
Sure it will be caught in C#, because its build model assumes the existence of modules and everything is compiled to binary.
In C++ a similar compilation error would occur when compiling the translation unit into a library where the template is instantiated.
Of course, most templates being header only the error will only occur when instating it, but it will still blow on compilation and prevent the final generation of the exe, dll being produced.
Also errors related to semantic type check, independent of template arguments is relatively easy to achieve with unit tests.
I still fail to see how a generic system that doesn't offer partial specialization or meta-programming as being more powerful than templates.
I never said more powerful. I said stronger. In C++ you need unit tests to check something I can have statically proven in C#. And obviously you can't instantiate your template for all possible valid input types, because this number can be infinite.
C# type checks imply a performance hit and are an implementation detail. Nothing prevents a C# compiler to choose another one. It has nothing to do with generics vs templates.
For example Modula-3 and Ada compilers use the same approach as C++ for code generation of their generics.
So where is that example of something that can only be written with C# generics, but not with C++ templates?
A github gist maybe?