2013-10-03 3 views
0

Я думал, что параметры шаблона функции объявляются только идентификаторы классов, например:основные типы как функции шаблонов параметров

template<class T1, class T2> void fun(T1 a, T2 b){} 

, но я нашел другой пример, когда фундаментальный тип может быть использован в качестве параметра:

template<int R, int C> 
void fun(double (&arr)[R][C]) 
{ 
    for(int i = 0; i < R; ++i) 
    { 
      for(int j = 0; j < C; ++j) 
      { 
       cout<<arr[i][j]<<" "; 
      } 
      cout<<endl; 
    } 
} 

исполнения функции выглядит следующим образом:

fun(myArray); 

Как этот механизм работает? Не могли бы вы дать мне еще один пример, где фундаментальный тип может использоваться как параметр шаблона функции?

+3

'std :: array ' например. – juanchopanza

+1

Или [tuple получает] (http://en.cppreference.com/w/cpp/utility/tuple/get). – Danstahr

+3

Google * аргументы шаблона non-type * – Praetorian

ответ

2

В моих путешествиях, я нашел три основных использования для параметров шаблона как основных типов:

Один строит шаблон функции, которая принимает массив C-стиле. Это то, что вы опубликовали здесь, но чаще я видел это относится к char массивов, как и с:

template <size_t N, typename Char> 
string MakeString (Char const (&chars)[N]) 
{ 
    return string (chars, N); 
} 

int main() 
{ 
    string hi = MakeString ("Hello"); 
    cout << hi; 
} 

Другое использование строит вид дешевой системы атрибутов с помощью шаблона метапрограммирование.Например, предположим, что у вас есть куча классов, предназначенных для представления сообщений в некотором проводном протоколе, и для целей тестирования вы хотите сравнить фактический размер класса сообщений с тем, что спецификация говорит о том, какой размер должен быть.

enum MsgType 
{ 
    MsgType_Foo, 
    MsgType_Bar 
}; 

class FooMsg 
{ 
    uint32_t mField; 
    char mName [9]; 
}; 

class BarMsg 
{ 
    char mPrice [8]; 
    static const size_t SpecSize = 8; 
}; 

template <MsgType MT> size_t SpecSize(); 

template <> size_t SpecSize <MsgType_Foo>() 
{ 
    return 13; 
} 

template <> size_t SpecSize <MsgType_Bar>() 
{ 
    return 9; 
} 

int main() 
{ 
    assert (SpecSize <MsgType_Foo>() == sizeof (FooMsg)); 
    assert (SpecSize <MsgType_Bar>() == sizeof (BarMsg)); 
} 

Обратите внимание, что если вы запустите эту программу утверждения потерпит неудачу, если вы не сделаете что-то специфичен для каждой платформы (как #pragma pack (push, 1)), чтобы зафиксировать упаковку. Это одна из тех вещей, которые должны быть проверены!

Наконец, другое общее применение более конкретное, но техника может применяться к вашему собственному коду. В Boost.Tuple, а теперь и C++ 11 класс tuple использует функцию шаблона get<size_t> как средство доступа к элементам. Вот пример, взятый из en.cppreference.com:

#include <iostream> 
#include <string> 
#include <tuple> 

int main() 
{ 
    auto t = std::make_tuple(1, "Foo", 3.14); 
    // index-based access 
    std::cout << "(" << std::get<0>(t) << ", " << std::get<1>(t) 
       << ", " << std::get<2>(t) << ")\n"; 
} 

Я думаю, вы могли бы подумать об этом, как специализации обоих предыдущих примеров. Это еще более шаблонный метапрограммирующий обман, который оказывается весьма полезным в определенных ситуациях.

1

Похоже, вы, возможно, смущает тот факт, что шаблоны часто выглядят следующим образом:

template <class T> void Bar(T param); 

Существует synonym для класса в этом контексте, что является более описательным: TYPENAME. Это говорит о том, что любое имя типа может использоваться как параметр шаблона, включая примитивные типы или типы, которые генерируются из шаблона. Таким образом, вместо того, чтобы писать выше, вы можете написать:

template <typename T> void Bar(T param); 

В дополнение к типам вы можете передать some экземпляры типов в шаблоне, как вы продемонстрировали. Обычно это делается для установки размера массива в шаблоне класса, но имеет много других применений. Как отметил Praetorian в комментариях, вы можете найти дополнительную информацию, выполнив поиск non-type template arguments.

1

Несмотря на их синтаксис позволяет class для параметров шаблона, например: template <class T>, там никогда не было намерения, чтобы они были ограничены определенных пользователем типов.

Другими словами, вы можете всегда пройти фундаментальный тип в качестве параметра шаблона если пользователь не сделал что-то в коде внутри шаблона, чтобы предотвратить его, например, с static_assert или код внутри шаблона, вызывает функцию-член прошедшего типа.

Для параметров шаблона, отличного от типа, вы можете указать практически любой тип. Шаблон может быть создан с использованием значения этого типа или может быть преобразован в этот тип.


1. Вы можете использовать typename, если вы предпочитаете - некоторые люди предпочитают, так как это делает лучшую работу по передаче идеи, что имя любого типа допускается.

Смежные вопросы