Finish cxx version bump (#1948)
* `CMakeLists.txt`: drop hopefully obsolete code
* README.md: update
* Unbreak `BENCHMARK_HAS_CXX11` macro
835365f99a0b9ec338b6748f5ccb96a3673eeccc stopped defining it,
but didn't un-conditionalize the code guarded under it...
* Drop `BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK`
We no longer support such an old gcc version
* `docs/user_guide.md`: proofread
* Add a test to ensure that `benchmark.h` remains C++14 header
* Revert `[[maybe_unused]]` changes - it requires C++17
* Also support C++11 standard for using the library
I don't think we want to support C++03 though,
but i suppose C++11 is palatable, at least right now.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fd69060..4f67ff5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -306,17 +306,11 @@
endif()
endif(BENCHMARK_USE_LIBCXX)
-set(EXTRA_CXX_FLAGS "")
-if (WIN32 AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
- # Clang on Windows fails to compile the regex feature check under C++11
- set(EXTRA_CXX_FLAGS "-DCMAKE_CXX_STANDARD=14")
-endif()
-
# C++ feature checks
# Determine the correct regular expression engine to use
-cxx_feature_check(STD_REGEX ${EXTRA_CXX_FLAGS})
-cxx_feature_check(GNU_POSIX_REGEX ${EXTRA_CXX_FLAGS})
-cxx_feature_check(POSIX_REGEX ${EXTRA_CXX_FLAGS})
+cxx_feature_check(STD_REGEX)
+cxx_feature_check(GNU_POSIX_REGEX)
+cxx_feature_check(POSIX_REGEX)
if(NOT HAVE_STD_REGEX AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX)
message(FATAL_ERROR "Failed to determine the source files for the regular expression backend")
endif()
diff --git a/README.md b/README.md
index b30e57c..4e73025 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,7 @@
## Requirements
-The library can be used with C++03. However, it requires C++14 to build,
+The library can be used with C++11. However, it requires C++17 to build,
including compiler and standard library support.
_See [dependencies.md](docs/dependencies.md) for more details regarding supported
@@ -190,7 +190,7 @@
```bash
# Example on linux after running the build steps above. Assumes the
# `benchmark` and `build` directories are under the current directory.
-$ g++ mybenchmark.cc -std=c++14 -isystem benchmark/include \
+$ g++ mybenchmark.cc -std=c++11 -isystem benchmark/include \
-Lbenchmark/build/src -lbenchmark -lpthread -o mybenchmark
```
diff --git a/docs/user_guide.md b/docs/user_guide.md
index 3152762..b3c1cce 100644
--- a/docs/user_guide.md
+++ b/docs/user_guide.md
@@ -462,7 +462,7 @@
### Passing Arbitrary Arguments to a Benchmark
-In C++11 it is possible to define a benchmark that takes an arbitrary number
+It is possible to define a benchmark that takes an arbitrary number
of extra arguments. The `BENCHMARK_CAPTURE(func, test_case_name, ...args)`
macro creates a benchmark that invokes `func` with the `benchmark::State` as
the first argument followed by the specified `args...`.
@@ -563,22 +563,19 @@
state.SetBytesProcessed(
static_cast<int64_t>(state.iterations())*state.range(0));
}
-// C++03
-BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue<int>)->Range(1<<0, 1<<10);
-// C++11 or newer, you can use the BENCHMARK macro with template parameters:
+// You can use the BENCHMARK macro with template parameters:
BENCHMARK(BM_Sequential<WaitQueue<int>>)->Range(1<<0, 1<<10);
+// Old, legacy verbose C++03 syntax:
+BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue<int>)->Range(1<<0, 1<<10);
+
```
Three macros are provided for adding benchmark templates.
```c++
-#ifdef BENCHMARK_HAS_CXX11
#define BENCHMARK(func<...>) // Takes any number of parameters.
-#else // C++ < C++11
-#define BENCHMARK_TEMPLATE(func, arg1)
-#endif
#define BENCHMARK_TEMPLATE1(func, arg1)
#define BENCHMARK_TEMPLATE2(func, arg1, arg2)
```
@@ -740,12 +737,10 @@
state.counters["BytesProcessed"] = Counter(state.range(0), benchmark::Counter::kIsIterationInvariantRate, benchmark::Counter::OneK::kIs1024);
```
-When you're compiling in C++11 mode or later you can use `insert()` with
-`std::initializer_list`:
+You can use `insert()` with `std::initializer_list`:
<!-- {% raw %} -->
```c++
- // With C++11, this can be done:
state.counters.insert({{"Foo", numFoos}, {"Bar", numBars}, {"Baz", numBazs}});
// ... instead of:
state.counters["Foo"] = numFoos;
@@ -1249,7 +1244,7 @@
## A Faster KeepRunning Loop
-In C++11 mode, a ranged-based for loop should be used in preference to
+A ranged-based for loop should be used in preference to
the `KeepRunning` loop for running the benchmarks. For example:
```c++
diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h
index 663953d..c9a758b 100644
--- a/include/benchmark/benchmark.h
+++ b/include/benchmark/benchmark.h
@@ -191,6 +191,14 @@
TypeName(const TypeName&) = delete; \
TypeName& operator=(const TypeName&) = delete
+#ifdef BENCHMARK_HAS_CXX17
+#define BENCHMARK_UNUSED [[maybe_unused]]
+#elif defined(__GNUC__) || defined(__clang__)
+#define BENCHMARK_UNUSED __attribute__((unused))
+#else
+#define BENCHMARK_UNUSED
+#endif
+
// Used to annotate functions, methods and classes so they
// are not optimized by the compiler. Useful for tests
// where you expect loops to stay in place churning cycles
@@ -303,6 +311,18 @@
#endif // _MSC_VER_
namespace benchmark {
+
+namespace internal {
+#if (__cplusplus < 201402L || (defined(_MSC_VER) && _MSVC_LANG < 201402L))
+template <typename T, typename... Args>
+std::unique_ptr<T> make_unique(Args&&... args) {
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+#else
+using ::std::make_unique;
+#endif
+} // namespace internal
+
class BenchmarkReporter;
class State;
@@ -472,7 +492,7 @@
// Ensure that the standard streams are properly initialized in every TU.
BENCHMARK_EXPORT int InitializeStreams();
-[[maybe_unused]] static int stream_init_anchor = InitializeStreams();
+BENCHMARK_UNUSED static int stream_init_anchor = InitializeStreams();
} // namespace internal
@@ -1026,7 +1046,7 @@
}
struct State::StateIterator {
- struct [[maybe_unused]] Value {};
+ struct BENCHMARK_UNUSED Value {};
typedef std::forward_iterator_tag iterator_category;
typedef Value value_type;
typedef Value reference;
@@ -1371,7 +1391,7 @@
inline internal::Benchmark* RegisterBenchmark(const std::string& name,
internal::Function* fn) {
return internal::RegisterBenchmarkInternal(
- std::make_unique<internal::FunctionBenchmark>(name, fn));
+ benchmark::internal::make_unique<internal::FunctionBenchmark>(name, fn));
}
template <class Lambda>
@@ -1379,19 +1399,16 @@
using BenchType =
internal::LambdaBenchmark<typename std::decay<Lambda>::type>;
return internal::RegisterBenchmarkInternal(
- std::make_unique<BenchType>(name, std::forward<Lambda>(fn)));
+ benchmark::internal::make_unique<BenchType>(name,
+ std::forward<Lambda>(fn)));
}
-#if (!defined(BENCHMARK_GCC_VERSION) || BENCHMARK_GCC_VERSION >= 409)
template <class Lambda, class... Args>
internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn,
Args&&... args) {
return benchmark::RegisterBenchmark(
name, [=](benchmark::State& st) { fn(st, args...); });
}
-#else
-#define BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK
-#endif
// The base class for all fixture tests.
class Fixture : public internal::Benchmark {
@@ -1442,13 +1459,14 @@
#define BENCHMARK_PRIVATE_DECLARE(n) \
/* NOLINTNEXTLINE(misc-use-anonymous-namespace) */ \
static ::benchmark::internal::Benchmark const* const BENCHMARK_PRIVATE_NAME( \
- n) [[maybe_unused]]
+ n) BENCHMARK_UNUSED
#define BENCHMARK(...) \
BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \
(::benchmark::internal::RegisterBenchmarkInternal( \
- std::make_unique<::benchmark::internal::FunctionBenchmark>( \
- #__VA_ARGS__, __VA_ARGS__)))
+ benchmark::internal::make_unique< \
+ ::benchmark::internal::FunctionBenchmark>(#__VA_ARGS__, \
+ __VA_ARGS__)))
// Old-style macros
#define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a))
@@ -1469,11 +1487,12 @@
//}
// /* 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(_benchmark_) = \
- (::benchmark::internal::RegisterBenchmarkInternal( \
- std::make_unique<::benchmark::internal::FunctionBenchmark>( \
- #func "/" #test_case_name, \
+#define BENCHMARK_CAPTURE(func, test_case_name, ...) \
+ BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \
+ (::benchmark::internal::RegisterBenchmarkInternal( \
+ benchmark::internal::make_unique< \
+ ::benchmark::internal::FunctionBenchmark>( \
+ #func "/" #test_case_name, \
[](::benchmark::State& st) { func(st, __VA_ARGS__); })))
// This will register a benchmark for a templatized function. For example:
@@ -1484,22 +1503,24 @@
// BENCHMARK_TEMPLATE(BM_Foo, 1);
//
// will register BM_Foo<1> as a benchmark.
-#define BENCHMARK_TEMPLATE1(n, a) \
- BENCHMARK_PRIVATE_DECLARE(n) = \
- (::benchmark::internal::RegisterBenchmarkInternal( \
- std::make_unique<::benchmark::internal::FunctionBenchmark>( \
- #n "<" #a ">", n<a>)))
+#define BENCHMARK_TEMPLATE1(n, a) \
+ BENCHMARK_PRIVATE_DECLARE(n) = \
+ (::benchmark::internal::RegisterBenchmarkInternal( \
+ benchmark::internal::make_unique< \
+ ::benchmark::internal::FunctionBenchmark>(#n "<" #a ">", n<a>)))
-#define BENCHMARK_TEMPLATE2(n, a, b) \
- BENCHMARK_PRIVATE_DECLARE(n) = \
- (::benchmark::internal::RegisterBenchmarkInternal( \
- std::make_unique<::benchmark::internal::FunctionBenchmark>( \
- #n "<" #a "," #b ">", n<a, b>)))
+#define BENCHMARK_TEMPLATE2(n, a, b) \
+ BENCHMARK_PRIVATE_DECLARE(n) = \
+ (::benchmark::internal::RegisterBenchmarkInternal( \
+ benchmark::internal::make_unique< \
+ ::benchmark::internal::FunctionBenchmark>(#n "<" #a "," #b ">", \
+ n<a, b>)))
-#define BENCHMARK_TEMPLATE(n, ...) \
- BENCHMARK_PRIVATE_DECLARE(n) = \
- (::benchmark::internal::RegisterBenchmarkInternal( \
- std::make_unique<::benchmark::internal::FunctionBenchmark>( \
+#define BENCHMARK_TEMPLATE(n, ...) \
+ BENCHMARK_PRIVATE_DECLARE(n) = \
+ (::benchmark::internal::RegisterBenchmarkInternal( \
+ benchmark::internal::make_unique< \
+ ::benchmark::internal::FunctionBenchmark>( \
#n "<" #__VA_ARGS__ ">", n<__VA_ARGS__>)))
// This will register a benchmark for a templatized function,
@@ -1517,12 +1538,13 @@
#define BENCHMARK_TEMPLATE1_CAPTURE(func, a, test_case_name, ...) \
BENCHMARK_CAPTURE(func<a>, test_case_name, __VA_ARGS__)
-#define BENCHMARK_TEMPLATE2_CAPTURE(func, a, b, test_case_name, ...) \
- BENCHMARK_PRIVATE_DECLARE(func) = \
- (::benchmark::internal::RegisterBenchmarkInternal( \
- std::make_unique<::benchmark::internal::FunctionBenchmark>( \
- #func "<" #a "," #b ">" \
- "/" #test_case_name, \
+#define BENCHMARK_TEMPLATE2_CAPTURE(func, a, b, test_case_name, ...) \
+ BENCHMARK_PRIVATE_DECLARE(func) = \
+ (::benchmark::internal::RegisterBenchmarkInternal( \
+ benchmark::internal::make_unique< \
+ ::benchmark::internal::FunctionBenchmark>( \
+ #func "<" #a "," #b ">" \
+ "/" #test_case_name, \
[](::benchmark::State& st) { func<a, b>(st, __VA_ARGS__); })))
#define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \
@@ -1591,7 +1613,7 @@
#define BENCHMARK_PRIVATE_REGISTER_F(TestName) \
BENCHMARK_PRIVATE_DECLARE(TestName) = \
(::benchmark::internal::RegisterBenchmarkInternal( \
- std::make_unique<TestName>()))
+ benchmark::internal::make_unique<TestName>()))
// This macro will define and register a benchmark within a fixture class.
#define BENCHMARK_F(BaseClass, Method) \
diff --git a/test/BUILD b/test/BUILD
index e3558a9..9a26970 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -102,12 +102,28 @@
["*_test.cc"],
exclude = [
"*_assembly_test.cc",
+ "cxx11_test.cc",
"link_main_test.cc",
],
)
]
cc_test(
+ name = "cxx11_test",
+ size = "small",
+ srcs = ["cxx11_test.cc"],
+ copts = TEST_COPTS + ["-std=c++11"],
+ target_compatible_with = select({
+ "//:windows": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ }),
+ deps = [
+ ":output_test_helper",
+ "//:benchmark_main",
+ ],
+)
+
+cc_test(
name = "link_main_test",
size = "small",
srcs = ["link_main_test.cc"],
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index a7e7122..df575d9 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -73,6 +73,18 @@
endmacro(benchmark_add_test)
# Demonstration executable
+
+compile_benchmark_test_with_main(cxx11_test)
+if(DEFINED MSVC)
+ # MSVC does not really support C++11.
+ set_property(TARGET cxx11_test PROPERTY CXX_STANDARD 14)
+else()
+ set_property(TARGET cxx11_test PROPERTY CXX_STANDARD 11)
+endif()
+set_property(TARGET cxx11_test PROPERTY CXX_STANDARD_REQUIRED ON)
+set_property(TARGET cxx11_test PROPERTY CXX_EXTENSIONS OFF)
+benchmark_add_test(NAME cxx11_test COMMAND cxx11_test --benchmark_min_time=0.01s)
+
compile_benchmark_test(benchmark_test)
benchmark_add_test(NAME benchmark COMMAND benchmark_test --benchmark_min_time=0.01s)
diff --git a/test/basic_test.cc b/test/basic_test.cc
index c3ac494..b51494b 100644
--- a/test/basic_test.cc
+++ b/test/basic_test.cc
@@ -143,7 +143,6 @@
}
BENCHMARK(BM_RangedFor);
-#ifdef BENCHMARK_HAS_CXX11
template <typename T>
void BM_OneTemplateFunc(benchmark::State& state) {
auto arg = state.range(0);
@@ -168,8 +167,6 @@
BENCHMARK(BM_TwoTemplateFunc<int, double>)->Arg(1);
BENCHMARK(BM_TwoTemplateFunc<double, int>)->Arg(1);
-#endif // BENCHMARK_HAS_CXX11
-
// Ensure that StateIterator provides all the necessary typedefs required to
// instantiate std::iterator_traits.
static_assert(
diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc
index e00f153..141f286 100644
--- a/test/benchmark_test.cc
+++ b/test/benchmark_test.cc
@@ -131,9 +131,7 @@
->Range(1 << 0, 1 << 10);
BENCHMARK_TEMPLATE(BM_Sequential, std::list<int>)->Range(1 << 0, 1 << 10);
// Test the variadic version of BENCHMARK_TEMPLATE in C++11 and beyond.
-#ifdef BENCHMARK_HAS_CXX11
BENCHMARK_TEMPLATE(BM_Sequential, std::vector<int>, int)->Arg(512);
-#endif
static void BM_StringCompare(benchmark::State& state) {
size_t len = static_cast<size_t>(state.range(0));
@@ -225,8 +223,6 @@
BENCHMARK(BM_ManualTiming)->Range(1, 1 << 14)->UseRealTime();
BENCHMARK(BM_ManualTiming)->Range(1, 1 << 14)->UseManualTime();
-#ifdef BENCHMARK_HAS_CXX11
-
template <class... Args>
void BM_with_args(benchmark::State& state, Args&&...) {
for (auto _ : state) {
@@ -267,8 +263,6 @@
BENCHMARK_TEMPLATE1_CAPTURE(BM_template1_capture, void, foo, 24UL);
BENCHMARK_CAPTURE(BM_template1_capture<void>, foo, 24UL);
-#endif // BENCHMARK_HAS_CXX11
-
static void BM_DenseThreadRanges(benchmark::State& st) {
switch (st.range(0)) {
case 1:
diff --git a/test/cxx11_test.cc b/test/cxx11_test.cc
new file mode 100644
index 0000000..db1a993
--- /dev/null
+++ b/test/cxx11_test.cc
@@ -0,0 +1,12 @@
+#include "benchmark/benchmark.h"
+
+#if defined(_MSC_VER)
+#if _MSVC_LANG != 201402L
+// MSVC, even in C++11 mode, dooes not claim to be in C++11 mode.
+#error "Trying to compile C++11 test with wrong C++ standard"
+#endif // _MSVC_LANG
+#else // Non-MSVC
+#if __cplusplus != 201103L
+#error "Trying to compile C++11 test with wrong C++ standard"
+#endif // Non-MSVC
+#endif
diff --git a/test/donotoptimize_test.cc b/test/donotoptimize_test.cc
index 75db934..5c9a458 100644
--- a/test/donotoptimize_test.cc
+++ b/test/donotoptimize_test.cc
@@ -62,8 +62,6 @@
BitRef lval = BitRef::Make();
benchmark::DoNotOptimize(lval);
-#ifdef BENCHMARK_HAS_CXX11
// Check that accept rvalue.
benchmark::DoNotOptimize(BitRef::Make());
-#endif
}
diff --git a/test/register_benchmark_test.cc b/test/register_benchmark_test.cc
index e443ab7..1a18814 100644
--- a/test/register_benchmark_test.cc
+++ b/test/register_benchmark_test.cc
@@ -77,7 +77,6 @@
// Note: GCC <= 4.8 do not support this form of RegisterBenchmark because they
// reject the variadic pack expansion of lambda captures.
//----------------------------------------------------------------------------//
-#ifndef BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK
void BM_extra_args(benchmark::State& st, const char* label) {
for (auto _ : st) {
@@ -95,8 +94,6 @@
const int dummy2 = RegisterFromFunction();
ADD_CASES({"test1", "One"}, {"test2", "Two"}, {"test3", "Three"});
-#endif // BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK
-
//----------------------------------------------------------------------------//
// Test RegisterBenchmark with DISABLED_ benchmark
//----------------------------------------------------------------------------//
@@ -121,14 +118,11 @@
};
void TestRegistrationAtRuntime() {
-#ifdef BENCHMARK_HAS_CXX11
{
CustomFixture fx;
benchmark::RegisterBenchmark("custom_fixture", fx);
AddCases({std::string("custom_fixture")});
}
-#endif
-#ifndef BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK
{
const char* x = "42";
auto capturing_lam = [=](benchmark::State& st) {
@@ -139,7 +133,6 @@
benchmark::RegisterBenchmark("lambda_benchmark", capturing_lam);
AddCases({{"lambda_benchmark", x}});
}
-#endif
}
// Test that all benchmarks, registered at either during static init or runtime,