Skip to content
Snippets Groups Projects
Commit 847f72f3 authored by Steffen Müthing's avatar Steffen Müthing
Browse files

[Typetraits][Compatibility] Provide partial backwards compatibility for...

[Typetraits][Compatibility] Provide partial backwards compatibility for is_indexable on old GCC versions

Older GCC versions have some nasty bugs related to SFINAE and indexing
with operator[]. This patch adds a configuration check for those
problems and a partial backwards compatibility hack for those older
compilers that is sufficient for our current use case in the VTK
writer.
parent f0dec2ff
No related branches found
No related tags found
No related merge requests found
...@@ -217,6 +217,55 @@ check_cxx_source_compiles(" ...@@ -217,6 +217,55 @@ check_cxx_source_compiles("
" HAVE_STD_DECLVAL " HAVE_STD_DECLVAL
) )
# full support for is_indexable (checking whether a type supports operator[])
check_cxx_source_compiles("
#include <utility>
#include <type_traits>
#include <array>
template <class T>
typename std::add_rvalue_reference<T>::type declval();
namespace detail {
template<typename T, typename I, typename = int>
struct _is_indexable
: public std::false_type
{};
template<typename T, typename I>
struct _is_indexable<T,I,typename std::enable_if<(sizeof(declval<T>()[declval<I>()]) > 0),int>::type>
: public std::true_type
{};
}
template<typename T, typename I = std::size_t>
struct is_indexable
: public detail::_is_indexable<T,I>
{};
struct foo_type {};
int main()
{
double x;
std::array<double,4> y;
double z[5];
foo_type f;
static_assert(not is_indexable<decltype(x)>::value,\"scalar type\");
static_assert(is_indexable<decltype(y)>::value,\"indexable class\");
static_assert(is_indexable<decltype(z)>::value,\"array\");
static_assert(not is_indexable<decltype(f)>::value,\"not indexable class\");
static_assert(not is_indexable<decltype(y),foo_type>::value,\"custom index type\");
return 0;
}
" HAVE_IS_INDEXABLE_SUPPORT
)
cmake_pop_check_state() cmake_pop_check_state()
# find the threading library # find the threading library
......
...@@ -116,6 +116,9 @@ ...@@ -116,6 +116,9 @@
/* Define to 1 if C++11 std::declval() is supported */ /* Define to 1 if C++11 std::declval() is supported */
#cmakedefine HAVE_STD_DECLVAL 1 #cmakedefine HAVE_STD_DECLVAL 1
/* Define to 1 if the compiler properly supports testing for operator[] */
#cmakedefine HAVE_IS_INDEXABLE_SUPPORT 1
/* does the compiler support the keyword 'final'? */ /* does the compiler support the keyword 'final'? */
#cmakedefine HAVE_KEYWORD_FINAL 1 #cmakedefine HAVE_KEYWORD_FINAL 1
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <type_traits> #include <type_traits>
#include <dune/common/deprecated.hh> #include <dune/common/deprecated.hh>
#include <dune/common/std/utility.hh>
namespace Dune namespace Dune
{ {
...@@ -404,23 +405,123 @@ namespace Dune ...@@ -404,23 +405,123 @@ namespace Dune
static const bool value = true; static const bool value = true;
}; };
namespace {
template<typename T, typename I, decltype(*(static_cast<T*>(nullptr))[*(static_cast<T*>(nullptr))],0) = 0> #if defined(DOXYGEN) or HAVE_IS_INDEXABLE_SUPPORT
auto _is_indexable(T*) -> std::true_type;
#ifndef DOXYGEN
namespace detail {
template<typename T, typename I, typename = int>
struct _is_indexable
: public std::false_type
{};
template<typename T, typename I> template<typename T, typename I>
auto _is_indexable(void*) -> std::false_type; struct _is_indexable<T,I,typename std::enable_if<(sizeof(Std::declval<T>()[Std::declval<I>()]) > 0),int>::type>
: public std::true_type
{};
} }
#endif // DOXYGEN
//! Type trait to determine whether an instance of T has an operator[](I), i.e. whether //! Type trait to determine whether an instance of T has an operator[](I), i.e. whether
//! it can be indexed with an index of type I. //! it can be indexed with an index of type I.
/**
* \warning Not all compilers support testing for arbitrary index types. In particular, there
* are problems with GCC 4.4 and 4.5.
*/
template<typename T, typename I = std::size_t> template<typename T, typename I = std::size_t>
struct is_indexable struct is_indexable
: public decltype(_is_indexable<T,I>(static_cast<T*>(nullptr))) : public detail::_is_indexable<T,I>
{}; {};
#else // defined(DOXYGEN) or HAVE_IS_INDEXABLE_SUPPORT
// okay, here follows a mess of compiler bug workarounds...
// GCC 4.4 dies if we try to subscript a simple type like int and
// both GCC 4.4 and 4.5 don't like using arbitrary types as subscripts
// for macros.
// So we make sure to only ever attempt the SFINAE for operator[] for
// class types, and to make sure the compiler doesn't become overly eager
// we have to do some lazy evaluation tricks with nested templates and
// stuff.
// Let's get rid of GCC 4.4 ASAP!
namespace detail {
// simple wrapper template to support the lazy evaluation required
// in _is_indexable
template<typename T>
struct _lazy
{
template<typename U>
struct evaluate
{
typedef T type;
};
};
// default version, gets picked if SFINAE fails
template<typename T, typename = int>
struct _is_indexable
: public std::false_type
{};
// version for types supporting the subscript operation
template<typename T>
struct _is_indexable<T,decltype(Std::declval<T>()[0],0)>
: public std::true_type
{};
// helper struct for delaying the evaluation until we are sure
// that T is a class (i.e. until we are outside std::conditional
// below)
struct _check_for_index_operator
{
template<typename T>
struct evaluate
: public _is_indexable<T>
{};
};
}
// The rationale here is as follows:
// 1) If we have an array, we assume we can index into it. That isn't
// true if I isn't an integral type, but that's why we have the static assertion
// in the body - we could of course try and check whether I is integral, but I
// can't be arsed and want to provide a motivation to switch to a newer compiler...
// 2) If we have a class, we use SFINAE to check for operator[]
// 3) Otherwise, we assume that T does not support indexing
//
// In order to make sure that the compiler doesn't accidentally try the SFINAE evaluation
// on an array or a scalar, we have to resort to lazy evaluation.
template<typename T, typename I = std::size_t>
struct is_indexable
: public std::conditional<
std::is_array<T>::value,
detail::_lazy<std::true_type>,
typename std::conditional<
std::is_class<T>::value,
detail::_check_for_index_operator,
detail::_lazy<std::false_type>
>::type
>::type::template evaluate<T>::type
{
static_assert(std::is_same<I,std::size_t>::value,"Your compiler is broken and does not support checking for arbitrary index types");
};
#endif // defined(DOXYGEN) or HAVE_IS_INDEXABLE_SUPPORT
/** @} */ /** @} */
} }
#endif #endif
...@@ -8,6 +8,7 @@ install(PROGRAMS ...@@ -8,6 +8,7 @@ install(PROGRAMS
ax_lang_compiler_ms.m4 ax_lang_compiler_ms.m4
boost_fusion.m4 boost_fusion.m4
cxx11_compiler.m4 cxx11_compiler.m4
cxx11_is_indexable_support.m4
cxx0x_nullptr.m4 cxx0x_nullptr.m4
cxx11_constexpr.m4 cxx11_constexpr.m4
cxx11_final.m4 cxx11_final.m4
......
...@@ -14,6 +14,7 @@ ALLM4S = \ ...@@ -14,6 +14,7 @@ ALLM4S = \
cxx0x_nullptr.m4 \ cxx0x_nullptr.m4 \
cxx11_constexpr.m4 \ cxx11_constexpr.m4 \
cxx11_final.m4 \ cxx11_final.m4 \
cxx11_is_indexable_support.m4 \
cxx11_noexcept.m4 \ cxx11_noexcept.m4 \
cxx11_range_based_for.m4 \ cxx11_range_based_for.m4 \
cxx11_std_declval.m4 \ cxx11_std_declval.m4 \
......
# tests whether the compiler properly supports testing for operator[]
# the associated macro is called HAVE_IS_INDEXABLE_SUPPORT
AC_DEFUN([DUNE_CXX11_IS_INDEXABLE_SUPPORT_CHECK],[
AC_CACHE_CHECK([whether the compiler properly supports testing for operator[[]]],
dune_cv_cxx11_is_indexable_support,
[
AC_REQUIRE([AC_PROG_CXX])
AC_REQUIRE([CXX11])
AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM(
[
#include <utility>
#include <type_traits>
#include <array>
template <class T>
typename std::add_rvalue_reference<T>::type declval();
namespace detail {
template<typename T, typename I, typename = int>
struct _is_indexable
: public std::false_type
{};
template<typename T, typename I>
struct _is_indexable<T,I,typename std::enable_if<(sizeof(declval<T>()[[declval<I>()]]) > 0),int>::type>
: public std::true_type
{};
}
template<typename T, typename I = std::size_t>
struct is_indexable
: public detail::_is_indexable<T,I>
{};
struct foo_type {};
],[
double x;
std::array<double,4> y;
double z[[5]];
foo_type f;
static_assert(not is_indexable<decltype(x)>::value,"scalar type");
static_assert(is_indexable<decltype(y)>::value,"indexable class");
static_assert(is_indexable<decltype(z)>::value,"array");
static_assert(not is_indexable<decltype(f)>::value,"not indexable class");
static_assert(not is_indexable<decltype(y),foo_type>::value,"custom index type");
return 0;
])],
dune_cv_cxx11_is_indexable_support=yes,
dune_cv_cxx11_is_indexable_support=no)
AC_LANG_POP
])
if test "$dune_cv_cxx11_is_indexable_support" = yes; then
AC_DEFINE(HAVE_IS_INDEXABLE_SUPPORT, 1,
[Define to 1 if the compiler properly supports testing for operator[[]]])
fi
])
...@@ -28,6 +28,7 @@ AC_DEFUN([DUNE_COMMON_CHECKS], ...@@ -28,6 +28,7 @@ AC_DEFUN([DUNE_COMMON_CHECKS],
AC_REQUIRE([DUNE_CHECKFINAL]) AC_REQUIRE([DUNE_CHECKFINAL])
AC_REQUIRE([DUNE_CHECKUNUSED]) AC_REQUIRE([DUNE_CHECKUNUSED])
AC_REQUIRE([DUNE_CXX11_STD_DECLVAL_CHECK]) AC_REQUIRE([DUNE_CXX11_STD_DECLVAL_CHECK])
AC_REQUIRE([DUNE_CXX11_IS_INDEXABLE_SUPPORT_CHECK])
AC_REQUIRE([DUNE_CHECK_CXA_DEMANGLE]) AC_REQUIRE([DUNE_CHECK_CXA_DEMANGLE])
AC_REQUIRE([DUNE_SET_MINIMAL_DEBUG_LEVEL]) AC_REQUIRE([DUNE_SET_MINIMAL_DEBUG_LEVEL])
AC_REQUIRE([DUNE_PATH_XDR]) AC_REQUIRE([DUNE_PATH_XDR])
...@@ -40,7 +41,7 @@ AC_DEFUN([DUNE_COMMON_CHECKS], ...@@ -40,7 +41,7 @@ AC_DEFUN([DUNE_COMMON_CHECKS],
]) ])
DUNE_ADD_MODULE_DEPS([dune-common], [STDTHREAD], [${STDTHREAD_CPPFLAGS}], DUNE_ADD_MODULE_DEPS([dune-common], [STDTHREAD], [${STDTHREAD_CPPFLAGS}],
[${STDTHREAD_LDFLAGS}], [${STDTHREAD_LIBS}]) [${STDTHREAD_LDFLAGS}], [${STDTHREAD_LIBS}])
dnl check for programs dnl check for programs
AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_PROG_CC])
# add -Wall if the compiler is gcc # add -Wall if the compiler is gcc
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment