Читаем Thinking In C++. Volume 2: Practical Programming полностью

You can always use such explicit function template specification as in the example above, but it is often convenient to leave off the template arguments and let the compiler deduce them from the function arguments, like this:.

int z = min(i, j);

If both i and j are ints, the compiler knows that you need min, which it then instantiates automatically. The types must be identical, because the template was originally specified with only one template type argument used for both function parameters. No standard conversions are applied for function arguments whose type is specified by a template parameter. For example, if you wanted to find the minimum of an int and a double, the following attempt at a call to min would fail:.

int z = min(x, j); // x is a double

Since x and j are distinct types, no single parameter matches the template parameter T in the definition of min; so the call does not match the template declaration. You can work around this difficulty by casting one argument to the other’s type or by reverting to the fully-specified call syntax, as in:.

int z = min(x, j);

This tells the compiler to generate the double version of min, after which j can be promoted to a double by normal standard conversion rules (because the function min(const double&, const double&) would then exist).

You might be tempted to require two parameters for min, allowing the types of the arguments to be independent, like this:

template

const T& min(const T& a, const U& b) {

  return (a < b) ? a : b;

}

This is often a good strategy, but in this case it is problematic because min must return a value, and there is no satisfactory way to determine which type it should be (T or U?).

If the return type of a function template is an independent template parameter, you must always specify its type explicitly when you call it, since there is no argument from which to deduce it. Such is the case with the fromString template below.

//: C05:StringConv.h

#ifndef STRINGCONV_H

#define STRINGCONV_H

// Function templates to convert to and from strings

#include

#include

template

T fromString(const std::string& s) {

  std::istringstream is(s);

  T t;

  is >> t;

  return t;

}

template

std::string toString(const T& t) {

  std::ostringstream s;

  s << t;

  return s.str();

}

#endif // STRINGCONV_H ///:~

These function templates provide conversions to and from std:: string for any types that provide a stream inserter or extractor, respectively. Here’s a test program that includes the use of the standard library complex number type:.

//: C05:StringConvTest.cpp

#include "StringConv.h"

#include

#include

using namespace std;

int main() {

  int i = 1234;

  cout << "i == \"" << toString(i) << "\"\n";

  float x = 567.89;

  cout << "x == \"" << toString(x) << "\"\n";

  complex c(1.0, 2.0);

  cout << "c == \"" << toString(c) << "\"\n";

  cout << endl;

  i = fromString(string("1234"));

  cout << "i == " << i << endl;

  x = fromString(string("567.89"));

  cout << "x == " << x << endl;

  c = fromString< complex >(string("(1.0,2.0)"));

  cout << "c == " << c << endl;

} ///:~

The output is what you’d expect:.

i == "1234"

x == "567.89"

c == "(1,2)"

i == 1234

x == 567.89

c == (1,2)

Notice that in each of the instantiations of fromString, the template parameter is specified in the call. If you have a function template with template parameters for the parameter types as well as the return types, it is important to declare the return type parameter first; otherwise you won’t be able to omit the type parameters for the function parameters. As an illustration, consider the following well-known function template:[51] 

//: C05:ImplicitCast.cpp

template

R implicit_cast(const P& p) {

  return p;

}

int main() {

  int i = 1;

  float x = implicit_cast(i);

  int j = implicit_cast(x);

  // char* p = implicit_cast(i);

} ///:~

If you interchange R and P in the template parameter list near the top of the file, it will be impossible to compile this program because the return type will remain unspecified (since the first template parameter would be the function’s parameter type). The last line (which is commented out) is illegal because there is no standard conversion from int to char*; implicit_cast is for revealing in your code conversions that are allowed naturally.

With a little care you can even deduce array dimensions. The following example has an array-initialization function template (init2) that does just that.

//: C05:ArraySize.cpp

#include

using std::size_t;

template

void init1(T a[R][C]) {

  for (size_t i = 0; i < R; ++i)

    for (size_t j = 0; j < C; ++j)

      a[i][j] = T();

}

template

void init2(T (&a)[R][C]) {  // reference parameter

  for (size_t i = 0; i < R; ++i)

    for (size_t j = 0; j < C; ++j)

      a[i][j] = T();

}

int main() {

  int a[10][20];

  init1<10,20>(a);  // must specify

  init2(a);         // sizes deduced

} ///:~

Перейти на страницу:

Похожие книги

3ds Max 2008
3ds Max 2008

Одни уверены, что нет лучшего способа обучения 3ds Мах, чем прочитать хорошую книгу. Другие склоняются к тому, что эффективнее учиться у преподавателя, который показывает, что и как нужно делать. Данное издание объединяет оба подхода. Его цель – сделать освоение 3ds Мах 2008 максимально быстрым и результативным. Часто после изучения книги у читателя возникают вопросы, почему не получился тот или иной пример. Видеокурс – это гарантия, что такие вопросы не возникнут: ведь автор не только рассказывает, но и показывает, как нужно работать в 3ds Мах.В отличие от большинства интерактивных курсов, где работа в 3ds Мах иллюстрируется на кубиках-шариках, данный видеокурс полностью практический. Все приемы работы с инструментами 3ds Мах 2008 показаны на конкретных примерах, благодаря чему после просмотра курса читатель сможет самостоятельно выполнять даже сложные проекты.

Владимир Антонович Верстак , Владимир Верстак

Программирование, программы, базы данных / Программное обеспечение / Книги по IT