diff --git a/.travis.yml b/.travis.yml index 647a1c1..d2e4d9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -128,7 +128,7 @@ matrix: sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-5.0 - - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-4.0 main' + - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main' key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' - env: COMPILER=clang++-5.0 BUILD_TYPE=Release diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ab5e44..e96fb64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,20 +14,31 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(GSL_STANDALONE_PROJECT ON) endif () + +include(CheckCXXCompilerFlag) +if (NOT MSVC) + CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14) +else() + CHECK_CXX_COMPILER_FLAG("-std:c++14" COMPILER_SUPPORTS_CXX14) +endif() + # when minimum version required is 3.8.0 remove if below # both branches do exactly the same thing if (CMAKE_VERSION VERSION_LESS 3.7.9) if (NOT MSVC) - include(CheckCXXCompilerFlag) - CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14) if(COMPILER_SUPPORTS_CXX14) target_compile_options(GSL INTERFACE "-std=c++14") else() message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++14 support. Please use a different C++ compiler.") endif() + else() + if(COMPILER_SUPPORTS_CXX14) + target_compile_options(GSL INTERFACE "-std:c++14") + else() + message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++14 support. Please use a different C++ compiler.") + endif() endif() else () - # set the GSL library to be compiled only with c++14 target_compile_features(GSL INTERFACE cxx_std_14) # on *nix systems force the use of -std=c++XX instead of -std=gnu++XX (default) set(CMAKE_CXX_EXTENSIONS OFF) diff --git a/include/gsl/pointers b/include/gsl/pointers index ad15ce3..69499d6 100644 --- a/include/gsl/pointers +++ b/include/gsl/pointers @@ -77,6 +77,12 @@ public: Expects(ptr_ != nullptr); } + template ::value>> + constexpr explicit not_null(T u) : ptr_(u) + { + Expects(ptr_ != nullptr); + } + template ::value>> constexpr not_null(const not_null& other) : not_null(other.get()) { diff --git a/tests/notnull_tests.cpp b/tests/notnull_tests.cpp index fa99bb7..1cb9c10 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -112,6 +112,7 @@ struct NonCopyableNonMovable }; bool helper(not_null p) { return *p == 12; } +bool helper_const(not_null p) { return *p == 12; } TEST_CASE("TestNotNullConstructors") { @@ -328,4 +329,62 @@ TEST_CASE("TestNotNullCustomPtrComparison") CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); } + +#if defined(__cplusplus) && (__cplusplus >= 201703L) +TEST_CASE("TestNotNullConstructorTypeDeduction") +{ + { + int i = 42; + + not_null x{&i}; + helper(not_null{&i}); + helper_const(not_null{&i}); + + CHECK(*x == 42); + } + + { + int i = 42; + int* p = &i; + + not_null x{p}; + helper(not_null{p}); + helper_const(not_null{p}); + + CHECK(*x == 42); + } + + { + auto workaround_macro = []() { + int* p1 = nullptr; + not_null x{p1}; + }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } + + { + auto workaround_macro = []() { + const int* p1 = nullptr; + not_null x{p1}; + }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } + + { + int* p = nullptr; + + CHECK_THROWS_AS(helper(not_null{p}), fail_fast); + CHECK_THROWS_AS(helper_const(not_null{p}), fail_fast); + } + +#ifdef CONFIRM_COMPILATION_ERRORS + { + not_null x{nullptr}; + helper(not_null{nullptr}); + helper_const(not_null{nullptr}); + } +#endif +} +#endif // #if defined(__cplusplus) && (__cplusplus >= 201703L) + static_assert(std::is_nothrow_move_constructible>::value, "not_null must be no-throw move constructible");