Added template argument deduction for not_null (#689)

* Added template  argument deduction for not_null

This allows compilers with c++17 support to infer template
instantiation types when calling not_null constructor:

    int foo(not_null<const int*> x);

    int main()
    {
        int t = 0;
        not_null x{ &t };
        return foo(not_null{ &t });
    }

* replaced deduction guides by a simple constructor

* Updated tests

* fixed check for availability of std::byte

* testing c++1z on clang

* fixed cmakelists extra endif

* include cstddef header for clang and gcc in pointers

* fixed a typo

* fix missing nullptr_t type

* fixed typo in CMakeLists.tst

* change approach to c++17 testing, step one: revert cmake testing, update clang5.0 package

removed using latest c++ due to clang5.0 failing,
update clang5.0 travis config to use llvm-toolchain-trusty-5.0

* addressed comments
This commit is contained in:
Anna Gringauze 2018-06-07 13:36:56 -07:00 committed by GitHub
parent 75ad0c1b40
commit cb2d1af89a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 80 additions and 4 deletions

View File

@ -128,7 +128,7 @@ matrix:
sources: sources:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
- llvm-toolchain-trusty-5.0 - 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' key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- env: COMPILER=clang++-5.0 BUILD_TYPE=Release - env: COMPILER=clang++-5.0 BUILD_TYPE=Release

View File

@ -14,20 +14,31 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(GSL_STANDALONE_PROJECT ON) set(GSL_STANDALONE_PROJECT ON)
endif () 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 # when minimum version required is 3.8.0 remove if below
# both branches do exactly the same thing # both branches do exactly the same thing
if (CMAKE_VERSION VERSION_LESS 3.7.9) if (CMAKE_VERSION VERSION_LESS 3.7.9)
if (NOT MSVC) if (NOT MSVC)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14)
if(COMPILER_SUPPORTS_CXX14) if(COMPILER_SUPPORTS_CXX14)
target_compile_options(GSL INTERFACE "-std=c++14") target_compile_options(GSL INTERFACE "-std=c++14")
else() else()
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++14 support. Please use a different C++ compiler.") message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++14 support. Please use a different C++ compiler.")
endif() 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() endif()
else () else ()
# set the GSL library to be compiled only with c++14
target_compile_features(GSL INTERFACE cxx_std_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) # on *nix systems force the use of -std=c++XX instead of -std=gnu++XX (default)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)

View File

@ -77,6 +77,12 @@ public:
Expects(ptr_ != nullptr); Expects(ptr_ != nullptr);
} }
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
constexpr explicit not_null(T u) : ptr_(u)
{
Expects(ptr_ != nullptr);
}
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>> template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr not_null(const not_null<U>& other) : not_null(other.get()) constexpr not_null(const not_null<U>& other) : not_null(other.get())
{ {

View File

@ -112,6 +112,7 @@ struct NonCopyableNonMovable
}; };
bool helper(not_null<int*> p) { return *p == 12; } bool helper(not_null<int*> p) { return *p == 12; }
bool helper_const(not_null<const int*> p) { return *p == 12; }
TEST_CASE("TestNotNullConstructors") TEST_CASE("TestNotNullConstructors")
{ {
@ -328,4 +329,62 @@ TEST_CASE("TestNotNullCustomPtrComparison")
CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); 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<not_null<void *>>::value, "not_null must be no-throw move constructible"); static_assert(std::is_nothrow_move_constructible<not_null<void *>>::value, "not_null must be no-throw move constructible");