diff --git a/dune/common/std/type_traits.hh b/dune/common/std/type_traits.hh
index b5c09a46a82dffe25b2fbfec6df46a028275318d..2862e028343fb04d807f033b595e82309c2b5d5c 100644
--- a/dune/common/std/type_traits.hh
+++ b/dune/common/std/type_traits.hh
@@ -1,7 +1,11 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
 #ifndef DUNE_COMMON_STD_TYPE_TRAITS_HH
 #define DUNE_COMMON_STD_TYPE_TRAITS_HH
 
 #include <type_traits>
+#include <dune/common/typetraits.hh>
+#include <dune/common/typeutilities.hh>
 
 namespace Dune
 {
@@ -95,6 +99,82 @@ namespace Std
 
 #endif
 
+
+  namespace Imp {
+
+    // If R is void we only need to check if F can be called
+    // with given Args... list. If this is not possible
+    // result_of_t is not defined and this overload is disabled.
+    template<class R, class F, class... Args,
+      std::enable_if_t<
+        std::is_same<void_t<std::result_of_t<F(Args...)>>, R>::value
+      , int> = 0>
+    std::true_type is_callable_helper(PriorityTag<2>)
+    { return {}; }
+
+    // Check if result of F(Args...) can be converted to R.
+    // If F cannot even be called with given Args... then
+    // result_of_t is not defined and this overload is disabled.
+    template<class R, class F, class... Args,
+      std::enable_if_t<
+        std::is_convertible<std::result_of_t<F(Args...)>, R>::value
+      , int> = 0>
+    std::true_type is_callable_helper(PriorityTag<1>)
+    { return {}; }
+
+    // If none of the above matches, F can either not be called
+    // with given Args..., or the result cannot be converted to
+    // void, or R is not void.
+    template<class R, class F, class... Args>
+    std::false_type is_callable_helper(PriorityTag<0>)
+    { return {}; }
+  }
+
+  /**
+   * \brief Traits class to check if function is callable
+   *
+   * \tparam D Function descriptor
+   * \tparam R Return value
+   *
+   * If D = F(Args...) this checks if F can be called with an
+   * argument list of type Args..., and if the return value can
+   * be converted to R. If R is void, any return type is accepted.
+   * The result is encoded by deriving from std::integral_constant<bool, result>.
+   *
+   * If D is not of the form D = F(Args...) this class is not defined.
+   *
+   * This implements std::is_callable as proposed in N4446 for C++17.
+   */
+  template <class D, class R= void>
+  struct is_callable;
+
+  /**
+   * \brief Traits class to check if function is callable
+   *
+   * \tparam D Function descriptor
+   * \tparam R Return value
+   *
+   * If D = F(Args...) this checks if F can be called with an
+   * argument list of type Args..., and if the return value can
+   * be converted to R. If R is void, any return type is accepted.
+   * The result is encoded by deriving from std::integral_constant<bool, result>.
+   *
+   * If D is not of the form D = F(Args...) this class is not defined.
+   *
+   * This implements std::is_callable as proposed in N4446 for C++17.
+   */
+  template <class F, class... Args, class R>
+  struct is_callable< F(Args...), R> :
+      decltype(Imp::is_callable_helper<R, F, Args...>(PriorityTag<42>()))
+  {};
+
+
+
+
+
+
+
+
 } // namespace Std
 
 } // namespace Dune
diff --git a/dune/common/test/CMakeLists.txt b/dune/common/test/CMakeLists.txt
index 2ca8e6f5e109b9f86cf6a5b3f377c4e3b33c34cd..76907985923cc8817d32c77674333acf05caa022 100644
--- a/dune/common/test/CMakeLists.txt
+++ b/dune/common/test/CMakeLists.txt
@@ -151,6 +151,9 @@ dune_add_test(SOURCES sllisttest.cc)
 dune_add_test(SOURCES stdapplytest.cc
               LINK_LIBRARIES dunecommon)
 
+dune_add_test(SOURCES stdtypetraitstest.cc
+              LINK_LIBRARIES dunecommon)
+
 dune_add_test(SOURCES streamtest.cc
               LINK_LIBRARIES dunecommon)
 
diff --git a/dune/common/test/stdtypetraitstest.cc b/dune/common/test/stdtypetraitstest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..82a587f3c9c6941b361a519d599d47fbfb887f71
--- /dev/null
+++ b/dune/common/test/stdtypetraitstest.cc
@@ -0,0 +1,75 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include <dune/common/std/type_traits.hh>
+
+#include <dune/common/test/testsuite.hh>
+
+
+int main()
+{
+  Dune::TestSuite test;
+
+  {
+    auto f = [](int i) { return 0; };
+    using F = decltype(f);
+
+    test.check(Dune::Std::is_callable<F(int)>() == true)
+      << "Dune::Std::is_callable does not accept copy from r-value";
+    test.check(Dune::Std::is_callable<F(int&)>() == true)
+      << "Dune::Std::is_callable does not accept copy from l-value reference";
+    test.check(Dune::Std::is_callable<F(int&&)>() == true)
+      << "Dune::Std::is_callable does not accept copy from r-value reference";
+
+    test.check(Dune::Std::is_callable<F(std::string)>() == false)
+      << "Dune::Std::is_callable accepts invalid argument type";
+    test.check(Dune::Std::is_callable<F(int, int)>() == false)
+      << "Dune::Std::is_callable accepts invalid argument count";
+    test.check(Dune::Std::is_callable<F(int), int>() == true)
+      << "Dune::Std::is_callable does not accept valid return type";
+    test.check(Dune::Std::is_callable<F(int), std::string>() == false)
+      << "Dune::Std::is_callable accepts invalid return type";
+  }
+
+  {
+    auto f = [](const int& i) {};
+    using F = decltype(f);
+
+    test.check(Dune::Std::is_callable<F(int)>() == true)
+      << "Dune::Std::is_callable does not accept const& temporary from r-value";
+    test.check(Dune::Std::is_callable<F(int&)>() == true)
+      << "Dune::Std::is_callable does not accept const& temporary from l-value reference";
+    test.check(Dune::Std::is_callable<F(int&&)>() == true)
+      << "Dune::Std::is_callable does not accept const& temporary from r-value reference";
+  }
+
+  {
+    auto f = [](int& i) {};
+    using F = decltype(f);
+
+    test.check(Dune::Std::is_callable<F(int)>() == false)
+      << "Dune::Std::is_callable accepts l-value reference from r-value";
+    test.check(Dune::Std::is_callable<F(int&)>() == true)
+      << "Dune::Std::is_callable does not accept l-value reference from l-value reference";
+    test.check(Dune::Std::is_callable<F(int&&)>() == false)
+      << "Dune::Std::is_callable accepts l-value reference from r-value reference";
+  }
+
+  {
+    auto f = [](int&& i) {};
+    using F = decltype(f);
+
+    test.check(Dune::Std::is_callable<F(int)>() == true)
+      << "Dune::Std::is_callable does not accept r-value reference from r-value";
+    test.check(Dune::Std::is_callable<F(int&)>() == false)
+      << "Dune::Std::is_callable accepts r-value reference from l-value reference";
+    test.check(Dune::Std::is_callable<F(int&&)>() == true)
+      << "Dune::Std::is_callable does not accept r-value reference from r-value reference";
+  }
+
+  return test.exit();
+}