开发者

what is the use of c++ non-type template values?

What is the use of c++ non-type template values? What can be done with this:

template <int I>
class MyClass
{
public:
    MyClass();
    .
    . //Use I;
    .
}

that can't be done with this:

class MyClass
{
    int I;
public:
    MyClass(int i) : I(i) {}
    .
    . //Use I
    .
}

The template version seems to me to create unnecessary overhead of the compiler creati开发者_Python百科ng two separate types of objects, with separate copies of every class method.


One use is that template argument deduction can be used to work out I, saving the programmer the bother:

template<typename T, size_t N>
T *end(T (&ra)[N]) {
    return ra + N;
}

int main() {
    std::string headings[] = {"name", "dob", "address"};
    std::ostream_iterator<std::string> output(std::cout, "\t")
    std::copy(headings, end(headings), output);
    // or
    std::vector<std::string> headingvec(headings, end(headings));

}

No messing with sizeof every time you want to use an array.

I'm pretty sure that the initial motivation for it was for class templates like std::bitset, though, as others have mentioned.


With template you can do this:

template <int I>
class MyClass
{
   int array[I];
}


the creation of separate types is actual a useful idom (google "int to type idiom "). But beyond that, the template version lets the compile know the value of the number at compile time, not runtime. Which means that there is a different set of possible optimizations that are available. Really the possibilities are tremendous, this feature basically makes c++ templates a full computing language in itself.

For a basic example of common usage, suppose you wanted to make a container that had a fixed size known at compile time. You couldn't implement that without non-type template params. Something like this:

array<int, 10> x; // create an object 10 int's big


The amount of things such a construct can be used are endless. One basic example would be boost::array, which specifies how large it will be through a non-type template parameter. It would not be possible to do the same in any other way (aggregate type, contents on stack).


The difference is that the template version gets expanded at compile time, so the integer compiles away to an implicit constant; in the non-templated version, the integer still exists at run time. In the templated version, MyClass<1> and MyClass<2> are two different, incompatible types, and trying to assign one to another will produce a compiler error.

A typical example for this is a generic vector class (the mathematical vector, not std::vector) where most methods work the same regardless of the vector's dimension (adding 2-space vectors and 4-space vectors is exactly the same operation), but some are only defined for special cases (cross product is only defined for 3-space and 7-space vectors). If you were to store the vector's dimension in a member variable, you'd have to do a runtime check each time an operation needs to be performed with possibly incompatible arguments (e.g. adding a 2-space vector to a 4-space vector), and you'd have to handle the resulting error at run-time.


With non type template parameters you really can do a lot of things. One such example, usually related to template meta-programming ( see Andrei Alexandrescu's book on this: "Modern C++ Design" ) is a template class that computes the factorial at compile time. Something like

template<int N>
class factorial
{
 public:
     enum { value = N * factorial<N-1>::value };
}

Then you can fully specialize your factorial class for 0, so it actually ends somewhere:

template<>
class factorial<0>
{
 public:
     enum { value = 1 };
}

Then, you can use this class to compute some factorial at compile-time like this:

int f4 = factorial<4>::value; // f4 will be 24 at compile time. Neat!

This may not be the most useful example, but you get the picture.

You can find this example on Wikipedia, where you can also read more on the subject.

Cheers.


One use is metaprogramming.

An example (stolen shamelessly from wikipedia) is a template that computes the power of a number at compile-time:

template <int N>
struct Factorial 
{
    enum { value = N * Factorial<N - 1>::value };
};

template <>
struct Factorial<0> 
{
    enum { value = 1 };
};

// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
    int x = Factorial<4>::value; // == 24
    int y = Factorial<0>::value; // == 1
}


it's useful if you want to define "constants" for types...

for example..

template <typename _foo, int _id>
class field
{
public:

  int id() { return _id; }

};

now when you declare an instance of field, you can encode it's id...

field<int, 10> _f1;
field<double, 11> _f2;

etc. why is this useful? consider protocols employed by third-parties, such as exchanges (say FAST/FIX etc.)


Illustration by example.

I am, at the moment, working on a Trie structure (by the way if anyone knows a good implementation...).

A Trie is basically a N-ary tree, with the first level being mostly complete and then getting sparser and sparser the deeper you delve in (this is not a propriety of the structure, it's just that most dictionaries have much more short words than longer ones).

I was thinking of using this feat of templates to minimize the number of nodes allocated. In a non templated way it would go:

class Node3; // contains N Node2
class Node2; // contains N Node1
class Node1; // contains N Node0
class Node0; // contains N Node
class Node;  // contains N POINTERS to Node

With the template I do:

template <size_t L> class Node; // contains N Node<L-1>
template <> class Node<0>;      // contains N Node
class Node;                     // contains N POINTERS to Node

And saves myself the boring task of writing a macro or copying the code over and over.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜