diff --git a/cmake/modules/CheckCXXFeatures.cmake b/cmake/modules/CheckCXXFeatures.cmake
index 0eb7a1769946574722ba452bbfa6cce0a58ced32..fe159bb42a99b4ec39001ddb9cebc2a37852faa0 100644
--- a/cmake/modules/CheckCXXFeatures.cmake
+++ b/cmake/modules/CheckCXXFeatures.cmake
@@ -27,85 +27,169 @@
 
 
 include(CMakePushCheckState)
-cmake_push_check_state()
+include(CheckCXXCompilerFlag)
+include(CheckCXXSourceCompiles)
 
-# test for C++14 flags
-if(NOT DISABLE_CXX_VERSION_CHECK)
-  # try to use compiler flag -std=c++14
-  include(CheckCXXCompilerFlag)
-  check_cxx_compiler_flag("-std=c++14" CXX_FLAG_CXX14)
+# C++ standard versions that this test knows about
+set(CXX_VERSIONS 17 14 11)
 
-  include(CheckCXXSourceCompiles)
-  cmake_push_check_state()
-  set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++14")
-  check_cxx_source_compiles("
-      #include <memory>
 
-      int main() {
-        std::make_unique<int>();
-      }
-    " CXX_LIB_SUPPORTS_CXX14)
-  cmake_pop_check_state()
-endif()
+# Compile tests for the different standard revisions; these test both the compiler
+# and the associated library to avoid problems like using a C++14 user-installed
+# compiler together with a non C++14-compliant stdlib from the system compiler.
 
-if(CXX_FLAG_CXX14 AND CXX_LIB_SUPPORTS_CXX14)
-  set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++14")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 ")
-  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++14 ")
-  set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -std=c++14 ")
-  set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++14 ")
-  set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -std=c++14 ")
-  set(CXX_STD14_FLAGS "-std=c++14")
-else()
-  if(NOT DISABLE_CXX_VERSION_CHECK)
-    # try to use compiler flag -std=c++1y for older compilers
-    check_cxx_compiler_flag("-std=c++1y" CXX_FLAG_CXX1Y)
+# we need to escape semicolons in the tests to be able to stick them into a list
+string(REPLACE ";" "\;" cxx_17_test
+  "
+  #include <type_traits>
 
-    include(CheckCXXSourceCompiles)
-    cmake_push_check_state()
-    set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++1y")
-    check_cxx_source_compiles("
-        #include <memory>
-
-        int main() {
-          std::make_unique<int>();
-        }
-      " CXX_LIB_SUPPORTS_CXX1Y)
-    cmake_pop_check_state()
+  // nested namespaces are a C++17 compiler feature
+  namespace A::B {
+    using T = int;
+  }
+
+  int main() {
+    // std::void_t is a C++17 library feature
+    return not std::is_same<void,std::void_t<A::B::T> >{};
+  }
+  ")
+
+string(REPLACE ";" "\;" cxx_14_test
+  "
+  #include <memory>
+
+  int main() {
+    // lambdas with auto parameters are C++14 - so this checks the compiler
+    auto l = [](auto x) { return x; };
+    // std::make_unique() is a C++14 library feature - this checks whether the
+    // compiler uses a C++14 compliant library.
+    auto v = std::make_unique<int>(l(0));
+    return *v;
+  }
+  ")
+
+string(REPLACE ";" "\;" cxx_11_test
+  "
+  #include <memory>
+
+  int main() {
+    // this checks both the compiler (by using auto) and the library (by using
+    // std::make_shared() for C++11 compliance at GCC 4.4 level.
+    auto v = std::make_shared<int>(0);
+    return *v;
+  }
+  ")
+
+# build a list out of the pre-escaped tests
+set(CXX_VERSIONS_TEST "${cxx_17_test}" "${cxx_14_test}" "${cxx_11_test}")
+
+# these are appended to "-std=c++" and tried in this order
+# note the escaped semicolons; that's necessary to create a nested list
+set(CXX_VERSIONS_FLAGS "17\;1z" "14\;1y" "11\;0x")
+
+# by default, we enable C++14 for now, but not C++17
+# The user can override this choice by explicitly setting this variable
+set(CXX_MAX_STANDARD 14 CACHE STRING "highest version of the C++ standard to enable")
+
+
+function(dune_require_cxx_standard)
+  include(CMakeParseArguments)
+
+  cmake_parse_arguments("" "" "MODULE;VERSION" "" ${ARGN})
+
+  if(_UNPARSED_ARGUMENTS)
+    message(WARNING "Unknown arguments in call to dune_require_cxx_standard(${ARGN})")
   endif()
-  if(CXX_FLAG_CXX1Y AND CXX_LIB_SUPPORTS_CXX1Y)
-    set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++1y" )
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y ")
-    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++1y ")
-    set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -std=c++1y ")
-    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++1y ")
-    set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -std=c++1y ")
-  set(CXX_STD14_FLAGS "-std=c++1y")
+
+  if(${_VERSION} GREATER ${CXX_MAX_SUPPORTED_STANDARD})
+
+    if(NOT _MODULE)
+      set(_MODULE "This module")
+    endif()
+
+    if(${_VERSION} GREATER ${CXX_MAX_STANDARD})
+      message(FATAL_ERROR "\
+${_MODULE} requires compiler support for C++${_VERSION}, but the build system is currently \
+set up to not allow newer language standards than C++${CXX_MAX_STANDARD}. Try setting the \
+CMake variable CXX_MAX_STANDARD to at least ${_VERSION}."
+        )
+    else()
+      message(FATAL_ERROR "
+${_MODULE} requires compiler support for C++${_VERSION}, but your compiler only supports \
+C++${CXX_MAX_SUPPORTED_STANDARD}."
+        )
+    endif()
   endif()
-endif()
+endfunction()
+
+
+# try to enable all of the C++ standards that we know about, in descending order
+if(NOT DISABLE_CXX_VERSION_CHECK)
+
+  foreach(version ${CXX_VERSIONS})
+
+    # skip versions that are newer than allowed
+    if(NOT(version GREATER CXX_MAX_STANDARD))
+
+      list(FIND CXX_VERSIONS ${version} version_index)
+      list(GET CXX_VERSIONS_FLAGS ${version_index} version_flags)
+
+      # First try whether the compiler accepts one of the command line flags for this standard
+      foreach(flag ${version_flags})
+
+        set(cxx_std_flag_works "cxx_std_flag_${flag}")
+        check_cxx_compiler_flag("-std=c++${flag}" ${cxx_std_flag_works})
 
-# test for C++11 flags
-if(NOT DISABLE_CXX_VERSION_CHECK
-   AND NOT ((CXX_FLAG_CXX14 AND CXX_LIB_SUPPORTS_CXX14)
-            OR (CXX_FLAG_CXX1Y AND CXX_LIB_SUPPORTS_CXX1Y)))
-  # try to use compiler flag -std=c++11
-  check_cxx_compiler_flag("-std=c++11" CXX_FLAG_CXX11)
-
-  if(CXX_FLAG_CXX11)
-    set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11")
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ")
-    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11 ")
-    set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -std=c++11 ")
-    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11 ")
-    set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -std=c++11 ")
-    set(CXX_STD11_FLAGS "-std=c++11")
-  else()
-    message(FATAL_ERROR "Your compiler does not seem to support C++11. If it does, please add any required flags to your CMAKE_CXX_FLAGS or set DISABLE_CXX_VERSION_CHECK.")
+        if(${cxx_std_flag_works})
+          set(cxx_std_flag "-std=c++${flag}")
+          break()
+        endif()
+
+      endforeach()
+
+      # and if it did, run the compile test
+      if(cxx_std_flag)
+
+        list(GET CXX_VERSIONS_TEST ${version_index} version_test)
+        set(test_compiler_output "compiler_supports_cxx${version}")
+
+        cmake_push_check_state()
+        set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${cxx_std_flag}")
+        check_cxx_source_compiles("${version_test}" ${test_compiler_output})
+        cmake_pop_check_state()
+
+        if(${test_compiler_output})
+          set(CXX_MAX_SUPPORTED_STANDARD ${version})
+          set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${cxx_std_flag} ")
+          break()
+        else()
+          # Wipe the variable, as this version of the standard doesn't seem to work
+          unset(cxx_std_flag)
+        endif()
+
+      endif()
+    endif()
+  endforeach()
+
+  if(NOT DEFINED CXX_MAX_SUPPORTED_STANDARD)
+    # Let's just assume every compiler at least claims C++03 compliance by now
+    message(WARNING "\
+Unable to determine C++ standard support for your compiler, falling back to C++03. \
+If you know that your compiler supports a newer version of the standard, please set the CMake \
+variable DISABLE_CXX_VERSION_CHECK to true and the CMake variable CXX_MAX_SUPPORTED_STANDARD \
+to the highest version of the standard supported by your compiler (e.g. 14). If your compiler \
+needs custom flags to switch to that standard version, you have to manually add them to \
+CMAKE_CXX_FLAGS."
+      )
+    set(CXX_MAX_SUPPORTED_STANDARD 3)
   endif()
+
 endif()
 
+# make sure we have at least C++11
+dune_require_cxx_standard(MODULE "DUNE" VERSION 11)
+
 # perform tests
-include(CheckCXXSourceCompiles)
 
 # __attribute__((unused))
 check_cxx_source_compiles("
@@ -230,8 +314,6 @@ check_cxx_source_compiles("
   )
 
 
-cmake_pop_check_state()
-
 # find the threading library
 # Use a copy FindThreads from CMake 3.1 due to its support of pthread
 if(NOT DEFINED THREADS_PREFER_PTHREAD_FLAG)
@@ -324,5 +406,3 @@ if(NOT STDTHREAD_WORKS)
     "STDTHREAD_LINK_FLAGS.  If you think this test is wrong, set the cache "
     "variable STDTHREAD_WORKS.")
 endif(NOT STDTHREAD_WORKS)
-
-cmake_pop_check_state()