Method templates for Fixtures introduced (#1967)
diff --git a/docs/user_guide.md b/docs/user_guide.md index 0bcfe15..5fc0db9 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md
@@ -677,6 +677,54 @@ // `DoubleTest` is now registered. ``` +If you want to use a method template for your fixtures, +which you instantiate afterward, use the following macros: + +* `BENCHMARK_TEMPLATE_METHOD_F(ClassName, Method)` +* `BENCHMARK_TEMPLATE_INSTANTIATE_F(ClassName, Method, ...)` + +With these macros you can define one method for several instantiations. +Example (using `MyFixture` from above): + +```c++ +// Defines `Test` using the class template `MyFixture`. +BENCHMARK_TEMPLATE_METHOD_F(MyFixture, Test)(benchmark::State& st) { + for (auto _ : st) { + ... + } +} + +// Instantiates and registers the benchmark `MyFixture<int>::Test`. +BENCHMARK_TEMPLATE_INSTANTIATE_F(MyFixture, Test, int)->Threads(2); +// Instantiates and registers the benchmark `MyFixture<double>::Test`. +BENCHMARK_TEMPLATE_INSTANTIATE_F(MyFixture, Test, double)->Threads(4); +``` + +Inside the method definition of `BENCHMARK_TEMPLATE_METHOD_F` the type `Base` refers +to the type of the instantiated fixture. +Accesses to members of the fixture must be prefixed by `this->`. + +`BENCHMARK_TEMPLATE_METHOD_F`and `BENCHMARK_TEMPLATE_INSTANTIATE_F` can only be used, +if the fixture does not use non-type template parameters. +If you want to pass values as template parameters, use e.g. `std::integral_constant`. +For example: + +```c++ +template<typename Sz> +class SizedFixture : public benchmark::Fixture { + static constexpr Size = Sz::value; + int myValue; +}; + +BENCHMARK_TEMPLATE_METHOD_F(SizedFixture, Test)(benchmark::State& st) { + for (auto _ : st) { + this->myValue = Base::Size; + } +} + +BENCHMARK_TEMPLATE_INSTANTIATE_F(SizedFixture, Test, std::integral_constant<5>)->Threads(2); +``` + <a name="custom-counters" /> ## Custom Counters
diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 5e40975..c4b5d89 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h
@@ -1631,6 +1631,36 @@ (::benchmark::internal::RegisterBenchmarkInternal( \ ::benchmark::internal::make_unique<TestName>())) +#define BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F(BaseClass, Method) \ + BaseClass##_##Method##_BenchmarkTemplate + +#define BENCHMARK_TEMPLATE_METHOD_F(BaseClass, Method) \ + template <class... Args> \ + class BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F(BaseClass, Method) \ + : public BaseClass<Args...> { \ + protected: \ + using Base = BaseClass<Args...>; \ + void BenchmarkCase(::benchmark::State&) override; \ + }; \ + template <class... Args> \ + void BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F( \ + BaseClass, Method)<Args...>::BenchmarkCase + +#define BENCHMARK_TEMPLATE_PRIVATE_INSTANTIATE_F(BaseClass, Method, \ + UniqueName, ...) \ + class UniqueName : public BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F( \ + BaseClass, Method)<__VA_ARGS__> { \ + public: \ + UniqueName() { this->SetName(#BaseClass "<" #__VA_ARGS__ ">/" #Method); } \ + }; \ + BENCHMARK_PRIVATE_DECLARE(BaseClass##_##Method##_Benchmark) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique<UniqueName>())) + +#define BENCHMARK_TEMPLATE_INSTANTIATE_F(BaseClass, Method, ...) \ + BENCHMARK_TEMPLATE_PRIVATE_INSTANTIATE_F( \ + BaseClass, Method, BENCHMARK_PRIVATE_NAME(tf), __VA_ARGS__) + // This macro will define and register a benchmark within a fixture class. #define BENCHMARK_F(BaseClass, Method) \ BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bde248f..b7a6ac4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt
@@ -180,6 +180,9 @@ compile_output_test(templated_fixture_test) benchmark_add_test(NAME templated_fixture_test COMMAND templated_fixture_test --benchmark_min_time=0.01s) +compile_output_test(templated_fixture_method_test) +benchmark_add_test(NAME templated_fixture_method_test COMMAND templated_fixture_method_test --benchmark_min_time=0.01s) + compile_output_test(user_counters_test) benchmark_add_test(NAME user_counters_test COMMAND user_counters_test --benchmark_min_time=0.01s)
diff --git a/test/templated_fixture_method_test.cc b/test/templated_fixture_method_test.cc new file mode 100644 index 0000000..06fc7d8 --- /dev/null +++ b/test/templated_fixture_method_test.cc
@@ -0,0 +1,26 @@ + +#include <cassert> +#include <memory> + +#include "benchmark/benchmark.h" + +template <typename T> +class MyFixture : public ::benchmark::Fixture { + public: + MyFixture() : data(0) {} + + T data; + + using type = T; +}; + +BENCHMARK_TEMPLATE_METHOD_F(MyFixture, Foo)(benchmark::State& st) { + for (auto _ : st) { + this->data += typename Base::type(1); + } +} + +BENCHMARK_TEMPLATE_INSTANTIATE_F(MyFixture, Foo, int); +BENCHMARK_TEMPLATE_INSTANTIATE_F(MyFixture, Foo, double); + +BENCHMARK_MAIN();