QuickCheck-подобный шаблон функции сравнительного анализа в C ++ - PullRequest
4 голосов
/ 17 января 2012

Вдохновленный элегантным способом автоматического создания (случайного) экземпляров заданного типа на Haskell, например, в QuickCheck, я пытаюсь выяснить, как написать как простой в использовании как возможный каркас бенчмаркинга в C ++. Я полагаю, что буду использовать шаблоны функций, возможно, с помощью новых функций в C ++ 11, таких как шаблоны с переменными параметрами. Я надеюсь, что мне нужно только указать функцию или, что еще лучше, шаблон функции и тип контейнера шаблона STL (а это, в свою очередь, value_type), совместимый с аргументом (ами) функции.

Я полагал, что сравнение функции с набором входов различного размера несколько похоже на то, как потоки настраиваются и порождаются в C ++ 11. Моей первой попыткой было бы скопировать конструктор класса thread и превратить его в функцию benchmark как

template< class Function, class ...Args >
inline
void benchmark( Function&& f, Args&&... args );

Я не уверен, должны ли мы использовать ссылки с r-значением здесь или нет. Однако f и args должны быть явно созданы до вызова benchmark, что приводит к громоздкому нефункциональному использованию.

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

namespace pnw
{
    template <template <typename> class Function, typename Container>
    inline
    void benchmark_container()
    {
        Function<typename Container::iterator> f;
        Container c(10);
        f(c.begin(), c.end());
    }
}

называется

typedef int T;
typedef std::vector<T> C;
pnw::benchmark_container<std::sort, C>();

Однако компиляция теперь выдает ошибку

tests/t_histogram.cpp: In function ‘void test_benchmark()’:
tests/t_histogram.cpp:56:44: error: no matching function for call to ‘benchmark_container()’
tests/t_histogram.cpp:56:44: note: candidate is:
tests/../benchmark.hpp:32:6: note: template<template<class> class Function, class Container> void pnw::benchmark_container()

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

Это правильный способ сделать это или это невозможно в C ++ 11? Я использую GCC-4.6.

1 Ответ

4 голосов
/ 17 января 2012

Если вам нужно поддерживать параметры с «более высоким родом», вы должны использовать параметры шаблона-шаблона .Кроме того, внутри шаблона значение f::g будет считаться значением, если оно не квалифицировано как typename.Поэтому вы должны написать:

template <template <typename> class Function, typename Container>  // <--
inline void benchmark_container()
{
    Function<typename Container::iterator> f;   // <--
    ...

(Все это доступно до C ++ 11.)


Редактировать: Но вызов

benchmark_container<std::sort, C>();

не будет работать, потому что std::sort - перегруженная функция шаблона, а не шаблон класса.Вы также не можете ссылаться только на std::sort, потому что это было бы неоднозначно.

Если вы хотите работать только с такими функциями, как std::sort, с которыми нет связанных контекстов, вы можете передать указатель на функцию для устранения неоднозначности с использованием перегрузки:

template <typename Container,
          void (*func)(typename Container::iterator, typename Container::iterator)>
inline void benchmark_container()
{
    Container c (10);
    func(c.begin(), c.end());
}

benchmark_container<std::vector<int>, std::sort>();

или

template <typename Container>
inline void benchmark_container(void (*func)(typename Container::iterator, typename Container::iterator))
{
    Container c (10);
    func(c.begin(), c.end());
}

benchmark_container<std::vector<int>>(std::sort);

или просто вручную выберите, какую перегрузку вы хотите использовать, что позволяет передавать объекты общих функций:

template <typename Container, typename F>
inline void benchmark_container(const F& function)
{
    Container c (10);
    function(c.begin(), c.end());
}

benchmark_container<std::vector<int>>(std::sort<std::vector<int>::iterator>);
...