what is a template from c++ intent?

Started by
10 comments, last by frob 9 years, 8 months ago

I wonder what is a template issued compiler object, is it one of the two following alternatives- and if yes- could you elaborate on anything of the one of the definitions alternatives it misses?

A template type of a variable in c++ compiling protocol is :

1 alternative : a variable of any type without any compiler ability to check validity of instructions with it?

2 alternative : a type of objects that share certain properties and the writer of code wishes to implement unified commands over them without need to derive them from common ancesting object in a strongly types language?

or both of them are totaly wrong?

Advertisement

Neither is really correct but 2 is closer to correct; 1 sounds more like a C-style macro.

Basically you can think of templates as type-safe macros. This is not altogether accurate but is a good first approximation.

In other words both macros and templates cause code to get generated. The compiler will do some work for you filling in what you mean. However, in the case macros the way that the preprocessor does this code generation is completely braindead: it doesn't know anything about the types involved it just pastes the arguments into the macro and if what comes out is garbage then so be it.

In the case of templates the compiler is checking types while it is doing the code generation.

but macro is just a missplaced continuing code with ability to replace in many places. Template is not. Wtf is template sad.png I am lost never needed to use it, never wished to use it, but I have been in an enviroment where it was a principle to get used. Isn't it just dangerous? As you said, the second alternative is quite close, so it allows one to implement instructions upon objects that do not share ancestors, are being of different types with certain matches, but share possible instructions validity in manner of members. But tamplates for me are such a thin ice.

Never ever I have used it actualy. What is it intended exactly for? The second alternative is the only best stuff I could come up with, but it opens missinterpretation that compiler cannot catch, making one's issues more difficult?

I am lost never needed to use it, never wished to use it, but I have been in an enviroment where it was a principle to get used. Isn't it just dangerous?


Search for "generic programming." They're super useful, by far the most important missing feature from any language that lacks them (C, Go, etc.).

The easy example in C++ is a std::vector or std::unique_ptr. It would totally suck to have to reimplement those over and over and over again for every type.

so it allows one to implement instructions upon objects that do not share ancestors


That is not a bad thing. Needing ancestor types to do things is _bad_, not good.

That said, C++17 (or around then) will have this thing called Concepts which are a way of constraining templates to only works on types that conform to a specific contract (without being forced to add ancestor types).

Sean Middleditch – Game Systems Engineer – Join my team!

A template is not a variable of any kind. It is not a macro.


I like to think of them as cookie cutters. A cookie cutter defines the shape of the cookie, and you can swap it out with sugar cookie dough, chocolate chip dough, peanut butter dough, oatmeal cookie dough, and any other flavor even if the person who made the cookie cutter hadn't thought about that flavor.

Similarly, templates are not classes by themselves. They are tools the compiler can adjust and manipulate to create code. The compiler can substitute any kind of typename it wants, even typenames that you did not plan on as the template author.

The compiler uses a template to generate code. You provide the typenames or values that are missing, and the compiler will generate a class or function or other content that uses what you provided to create source code for the class. Then it will compile that source code.

I was too expressive, sorry.

std::vector or std::unique_ptr

standard vectors just poses pointers. Right? Nothing further and they do not mess with a template stuff.

In the case of templates the compiler is checking types while it is doing the code generation.

It realy does not, and if it does..... nope, c++ cannot turn to a hell of a brain language can it?

Frob, did you ever fall for tamplate usage, or sticked to conforming compiler runtime code? You sure did Frob. Template= utopia!!! IT DOES

None of what you have said makes any sense.

At a basic level it's not rocket science.
Let's say you have a simple function


int Add(int a, int b) { return a + b; }

Now in non template C++ if you wanted to use that function to add floats or doubles, you'd need to write


float Add(float a, float b) { return a + b; }
double Add(double a, double b) { return a + b; }

ugh... repetition.

With a template you'd write


template <typename T>
T Add(T a, T b) { return a + b; }

when you want to use it, you would write


int x = Add<int>(1, 2);
double x = Add<double>(1.0, 2.0);

and the compiler would generate two functions for you.


int Add_int(int a, int b) { return a + b; }
double Add_double(double a, double b) { return a + b; }

These functions are only generated when you use them.

But let's say you had a class Bar


class Bar
{
};

if you tried to use your Add function with a Bar, the compiler would first generate a new add function


Bar Add_Bar(Bar a, Bar b) { return a + b; }

and then it would issue a compiler error (probably "no operator + found that accepts Bar and Bar")

On the other hand, if you tried to use an std::string with Add


std::string x = Add<std::string>("Hello, ", "World!");

// generated code
// std::string Add_string(std::string a, std::string b) { return a + b; }

this would work fine because std::string defines a + operator.

Now this is a very simple explanation, and leaves out all kinds of complexities like argument matching, SFINAE, specialisation, etc, but that's the basics of it.

if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight


Frob, did you ever fall for tamplate usage, or sticked to conforming compiler runtime code? You sure did Frob. Template= utopia!!! IT DOES

You.. do realize that templates are part of the language, right?

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”


standard vectors just poses pointers. Right? Nothing further and they do not mess with a template stuff.

Examine your compiler's included headers, and Ctrl+F/grep for "template". A five minute examination would have dispelled your counter-argument.

Another good use of generic programming is extensibility. Code that is templated can be used later in a way that the original coder had yet to conceive by substituting new types and values in place of the template parameters.

Last post on this topic, since I'm not sure this is going anywhere:

standard vectors just poses pointers. Right? Nothing further and they do not mess with a template stuff.


std::vector _is_ a template. That's why you use it like:

std::vector<int> foo;
The `<int>` bit is a clear sign that you're instantiating the `std::vector` class template over the `int` type parameter.

It realy does not, and if it does..... nope, c++ cannot turn to a hell of a brain language can it?


I'm not entirely sure I'm comprehending your objection, here.

The compiler works in various stages. After preprocessing, there's lexing, parsing, semantic analysis, IR generation, high-level optimization, IR lowering, low-level options, and finally actual machine code generation. Most of the work of verifying templates and instantiating them happen entirely in the earlier stages, though C++ requires some "fuzzines" between the classic stages due to some of its semantic oddities.

You can totally write templates that are constrained today using meta-programming techniques, particular SFINAE. Consider:

template <typename T>
auto lerp(float a, T lhs, T rhs) -> decltype(a * lhs + (1 - a) * rhs)
{
  return a * lhs + (1 - a) * rhs;
}
That function will thanks to SFINAE refuse to even instantiate for a type T that does not support operator +. If you try to call lerp on something like a pointer, you'll get a compiler error up front telling you that such operations are not supported. Trying to call it with T=void* for instance, Clang says:

10 : error: no matching function for call to 'lerp'
void* c = lerp(1.0f, a, b);
          ^~~~
2 : note: candidate template ignored: substitution failure [with T = void *]: invalid operands to binary expression ('float' and 'void *')
auto lerp(float a, T lhs, T rhs) -> decltype(a * lhs + (1 - a) * rhs)
                                             ^ ~
1 error generated.
Boost has a library library for Concept Checking that generalizes this support.

You can use std::enable_if, std::is_integral, and various other facilities and type traits (all templates!) instead of or in addition to decltype.

Once the Concepts TS is out (around C++17) you can also write the much simpler:

template <Arithmetic T>
T lerp(float a, T lhs, T rhs)
{
  return a * lhs + (1 - a) * rhs;
}
Note the `Arithmetic` which is a constraint, meaning that `T` must conform to the given constraint and not just be any generic type.

Sean Middleditch – Game Systems Engineer – Join my team!

This topic is closed to new replies.

Advertisement