diff --git a/src/util/nop.hpp b/src/util/nop.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6ec568b9d5fe9bfe4904b23ea6babcdf8b4ca84e --- /dev/null +++ b/src/util/nop.hpp @@ -0,0 +1,35 @@ +#pragma once + +/* + * Provide object that implicitly converts to + * a std::function object that does nothing but return a + * default-constructed type or void. + */ + +#include <functional> + +namespace nest { +namespace mc { +namespace util { + +struct nop_function_t { + template <typename R, typename... Args> + operator std::function<R (Args...)>() const { + return [](Args...) { return R{}; }; + } + + template <typename... Args> + operator std::function<void (Args...)>() const { + return [](Args...) { }; + } + + // keep clang happy: see CWG issue #253, + // http://open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#253 + constexpr nop_function_t() {} +}; + +static constexpr nop_function_t nop_function; + +} // namespace util +} // namespace mc +} // namespace nest diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index fb1b9369d4e38498c8953fc0ce2f16c1dbc715dc..83c537b26385b62ece833d59931ece57bc1cd8cc 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -21,6 +21,7 @@ set(TEST_SOURCES test_mask_stream.cpp test_matrix.cpp test_mechanisms.cpp + test_nop.cpp test_optional.cpp test_parameters.cpp test_point.cpp diff --git a/tests/unit/test_nop.cpp b/tests/unit/test_nop.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3571ad827555e23040658f3f7275f3bcf53d9d0 --- /dev/null +++ b/tests/unit/test_nop.cpp @@ -0,0 +1,75 @@ +#include "gtest.h" +#include "util/nop.hpp" + +using namespace nest::mc::util; + +TEST(nop, void_fn) { + std::function<void ()> f{nop_function}; + + EXPECT_TRUE(f); + f(); // should do nothing + + bool flag = false; + f = [&]() { flag = true; }; + f(); + EXPECT_TRUE(flag); + + flag = false; + f = nop_function; + f(); + EXPECT_FALSE(flag); + + // with some arguments + std::function<void (int, int)> g{nop_function}; + EXPECT_TRUE(g); + g(2, 3); // should do nothing + + int sum = 0; + g = [&](int a, int b) { sum = a+b; }; + g(2, 3); + EXPECT_EQ(5, sum); + + sum = 0; + g = nop_function; + g(2, 3); + EXPECT_EQ(0, sum); +} + +struct check_default { + int value = 100; + + check_default() = default; + explicit check_default(int n): value(n) {} +}; + +TEST(nop, default_return_fn) { + std::function<check_default ()> f{nop_function}; + + EXPECT_TRUE(f); + auto result = f(); + EXPECT_EQ(result.value, 100); + + f = []() { return check_default(17); }; + result = f(); + EXPECT_EQ(result.value, 17); + + f = nop_function; + result = f(); + EXPECT_EQ(result.value, 100); + + std::function<check_default (double, double)> g{nop_function}; + + EXPECT_TRUE(g); + result = g(1.4, 1.5); + EXPECT_EQ(result.value, 100); + + g = [](double x, double y) { return check_default{(int)(x*y)}; }; + result = g(1.4, 1.5); + EXPECT_EQ(result.value, 2); + + g = nop_function; + result = g(1.4, 1.5); + EXPECT_EQ(result.value, 100); + +} +