diff --git a/docs/user_guide.md b/docs/user_guide.md
index 95f57b3e..d22a9069 100644
--- a/docs/user_guide.md
+++ b/docs/user_guide.md
@@ -28,6 +28,8 @@
[Templated Benchmarks](#templated-benchmarks)
+[Templated Benchmarks that take arguments](#templated-benchmarks-with-arguments)
+
[Fixtures](#fixtures)
[Custom Counters](#custom-counters)
@@ -574,6 +576,30 @@ Three macros are provided for adding benchmark templates.
#define BENCHMARK_TEMPLATE2(func, arg1, arg2)
```
+
+
+## Templated Benchmarks that take arguments
+
+Sometimes there is a need to template benchmarks, and provide arguments to them.
+
+```c++
+template void BM_Sequential_With_Step(benchmark::State& state, int step) {
+ Q q;
+ typename Q::value_type v;
+ for (auto _ : state) {
+ for (int i = state.range(0); i-=step; )
+ q.push(v);
+ for (int e = state.range(0); e-=step; )
+ q.Wait(&v);
+ }
+ // actually messages, not bytes:
+ state.SetBytesProcessed(
+ static_cast(state.iterations())*state.range(0));
+}
+
+BENCHMARK_TEMPLATE1_CAPTURE(BM_Sequential, WaitQueue, Step1, 1)->Range(1<<0, 1<<10);
+```
+
## Fixtures
diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h
index 25c3eef7..5a1eef89 100644
--- a/include/benchmark/benchmark.h
+++ b/include/benchmark/benchmark.h
@@ -1523,7 +1523,7 @@ class Fixture : public internal::Benchmark {
// /* Registers a benchmark named "BM_takes_args/int_string_test` */
// BENCHMARK_CAPTURE(BM_takes_args, int_string_test, 42, std::string("abc"));
#define BENCHMARK_CAPTURE(func, test_case_name, ...) \
- BENCHMARK_PRIVATE_DECLARE(func) = \
+ BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \
(::benchmark::internal::RegisterBenchmarkInternal( \
new ::benchmark::internal::FunctionBenchmark( \
#func "/" #test_case_name, \
@@ -1560,6 +1560,31 @@ class Fixture : public internal::Benchmark {
#define BENCHMARK_TEMPLATE(n, a) BENCHMARK_TEMPLATE1(n, a)
#endif
+#ifdef BENCHMARK_HAS_CXX11
+// This will register a benchmark for a templatized function,
+// with the additional arguments specified by `...`.
+//
+// For example:
+//
+// template `
+// void BM_takes_args(benchmark::State& state, ExtraArgs&&... extra_args) {
+// [...]
+//}
+// /* Registers a benchmark named "BM_takes_args/int_string_test` */
+// BENCHMARK_TEMPLATE1_CAPTURE(BM_takes_args, void, int_string_test, 42,
+// std::string("abc"));
+#define BENCHMARK_TEMPLATE1_CAPTURE(func, a, test_case_name, ...) \
+ BENCHMARK_CAPTURE(func, test_case_name, __VA_ARGS__)
+
+#define BENCHMARK_TEMPLATE2_CAPTURE(func, a, b, test_case_name, ...) \
+ BENCHMARK_PRIVATE_DECLARE(func) = \
+ (::benchmark::internal::RegisterBenchmarkInternal( \
+ new ::benchmark::internal::FunctionBenchmark( \
+ #func "<" #a "," #b ">" \
+ "/" #test_case_name, \
+ [](::benchmark::State& st) { func(st, __VA_ARGS__); })))
+#endif // BENCHMARK_HAS_CXX11
+
#define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \
class BaseClass##_##Method##_Benchmark : public BaseClass { \
public: \
diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc
index 94590d5e..8b14017d 100644
--- a/test/benchmark_test.cc
+++ b/test/benchmark_test.cc
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
#include
#include
@@ -226,6 +227,31 @@ void BM_non_template_args(benchmark::State& state, int, double) {
}
BENCHMARK_CAPTURE(BM_non_template_args, basic_test, 0, 0);
+template
+void BM_template2_capture(benchmark::State& state, ExtraArgs&&... extra_args) {
+ static_assert(std::is_same::value, "");
+ static_assert(std::is_same::value, "");
+ static_assert(std::is_same::value, "");
+ unsigned int dummy[sizeof...(ExtraArgs)] = {extra_args...};
+ assert(dummy[0] == 42);
+ for (auto _ : state) {
+ }
+}
+BENCHMARK_TEMPLATE2_CAPTURE(BM_template2_capture, void, char*, foo, 42U);
+BENCHMARK_CAPTURE((BM_template2_capture), foo, 42U);
+
+template
+void BM_template1_capture(benchmark::State& state, ExtraArgs&&... extra_args) {
+ static_assert(std::is_same::value, "");
+ static_assert(std::is_same::value, "");
+ unsigned long dummy[sizeof...(ExtraArgs)] = {extra_args...};
+ assert(dummy[0] == 24);
+ for (auto _ : state) {
+ }
+}
+BENCHMARK_TEMPLATE1_CAPTURE(BM_template1_capture, void, foo, 24UL);
+BENCHMARK_CAPTURE(BM_template1_capture, foo, 24UL);
+
#endif // BENCHMARK_HAS_CXX11
static void BM_DenseThreadRanges(benchmark::State& st) {