шаблон для функции - PullRequest
       1

шаблон для функции

6 голосов
/ 21 мая 2011

Этот вопрос был задан мне в интервью:

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

Я не знаю точного ответа.Кто-нибудь может предложить?

Ответы [ 4 ]

12 голосов
/ 21 мая 2011

Они проверили вашу осведомленность о грядущем стандарте C ++. Новая функция называется «Шаблоны Variadic» и выглядит следующим образом:

template<typename... Args> void f( const Args&... args )
{
    // do something
}

Более сложные примеры см., Например, этот урок .

4 голосов
/ 21 мая 2011

В C ++ 03 любое количество аргументов в шаблоне функции невозможно.Однако для любого типа аргумента вы можете написать:

template<typename T, typename U> 
void f( const T & t, const U &u )
{
    //...
}
2 голосов
/ 21 мая 2011

Я согласен с тем, что они, скорее всего, искали вариационные шаблоны , но ради этого существуют разные подходы, которые можно использовать в C ++ 03:

Использование варианта типа

Использовать контейнер варианта типа. В этом случае boost::variant не будет работать, так как ограничивает количество типов, но вы можете использовать boost::any:

void foo( std::vector< boost::any > args );

По сравнению с шаблонами с переменными числами код пользователя будет намного более громоздким, поскольку вместо записи foo( a, b, c, d ) им придется вручную создавать вектор заранее. Синтаксис можно упростить с помощью переменных макросов (если их поддерживает компилятор) и / или вспомогательных шаблонных функций для адаптации синтаксиса, но это довольно легко может привести к путанице.

C-путь (не шаблон):

Используйте многоточие для записи функции, которая принимает неизвестное количество аргументов (и типов):

void foo( type x, ... )

У этого подхода много недостатков. Во-первых, он не является безопасным с точки зрения типов, компилятор не сможет обнаружить, что аргументы являются правильным числом или типами, и это неопределенное поведение, если какой-либо из аргументов имеет тип не POD, что ограничивает удобство использования с любой тип для типов POD, который может быть или не быть ограничивающим фактором (вы всегда можете передать указатель на объект, не являющийся POD). В целом, это сложнее обрабатывать и гораздо более подвержено ошибкам, поэтому его следует избегать.

Не отвечая на вопрос вообще

В очень немногих ситуациях одна функция должна иметь возможность принимать неизвестное количество аргументов неизвестного типа. Ведение журнала и ввод-вывод может потребовать этого, printf является таким примером. Но это может быть обработано в C ++ посредством перегрузки операторов (в частности, operator<<) и цепочки. В комментарии было предложено bind, так что да, идеальная пересылка в универсальном коде является одним из таких случаев, bind, std::thread ...

Он считает, что это хороший ответ для интервью, поскольку вы можете обсудить, какова реальная потребность в функции и есть ли лучшая альтернатива. Можно утверждать, что если в конце вам действительно нужен контейнер варианта типа, вы можете злоупотреблять перегрузкой операторов, чтобы упростить синтаксис. Примером этого может служить библиотека boost::assign, и в этих строках вы можете создать вспомогательный конструктор аргументов, например:

class args {
public:
   args() {}
   operator std::vector<boost::any>&() {
      return v;
   }
   template <typename T>
   args& operator,( T x ) {
      boost::any a = x;
      v.push_back( a );
      return *this;
   }
private:
   std::vector<boost::any> v;
};
// usage:
void foo( std::vector<boost::any> a ) {
   std::cout << "Received " << a.size() << " arguments" << std::endl;
}
int main() {
   foo(( args(), 1, 5.0, "a string", std::vector<int>(5,10) ));
}

Вариативные шаблоны

И, конечно же, лучший вариант - это компилятор c ++ 0x, который обрабатывает шаблоны с переменным числом аргументов, не требующий дополнительного кода и значительно упрощает написание обоих пользовательских кодов (непосредственно как обычный вызов функции). и реализация функции, что бы это ни было. В качестве мотивирующего примера можно построить vector<boost::any> с переменными аргументами:

typedef std::vector<boost::any> anyvector_t

// Stop condition, adding nothing at the end
void build_vector_impl( anyvector_t& ) {}

// Intermediate step, add a new argument to the vector and recurse:
template <typename Head, typename... Tail>
void build_vector_impl( anyvector_t& v, Head head, Tail... tail ) {
   v.push_back( boost::any(head) );
   build_vector_impl( v, tail... );
}

// Syntactic sugar: make it return the vector:
template <typename... Args>
anyvector_t build_vector( Args... args ) {
   anyvector_t res;
   build_vector_impl( res, args... );
   return res;
}
// Test:
int main() {
   std::cout << "Number of args: " 
             << build_vector( 1, 5, "Hi", std::vector<int>( 5, 10 ) ).size() 
             << std::endl;
}
0 голосов
/ 21 мая 2011

Это не о шаблонах. Речь идет о переменных аргументах.

http://www.eskimo.com/~scs/cclass/int/sx11b.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...