diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a39496e741c244e6998df28fb26b4d1d1afe5fd..c138a81876b7377d8e4ed48a3aa9f163b8586552 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,6 +139,9 @@ endif() ############################################################################################################################ +set( CMAKE_CXX_STANDARD 14 ) +set( CMAKE_CXX_STANDARD_REQUIRED ON ) +set( CMAKE_CXX_EXTENSIONS OFF ) ############################################################################################################################ ## @@ -172,7 +175,7 @@ if( CMAKE_CXX_COMPILER MATCHES "icpc" OR CMAKE_CXX_COMPILER_ARG1 MATCHES "icpc" MARK_AS_ADVANCED(XILD) if( CMAKE_VERSION VERSION_LESS 3.6.0 ) set( CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14" ) - add_flag ( CMAKE_CXX_FLAGS ${CMAKE_CXX14_STANDARD_COMPILE_OPTION} ) + add_flag ( CMAKE_CXX_FLAGS ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION} ) endif() else() option ( WALBERLA_CXX_COMPILER_IS_INTEL "Use Intel compiler" OFF ) @@ -278,10 +281,6 @@ if ( WALBERLA_PROFILE_USE ) endif() endif() -set( CMAKE_CXX_STANDARD 14 ) -set( CMAKE_CXX_STANDARD_REQUIRED ON ) -set( CMAKE_CXX_EXTENSIONS OFF ) - # common flags for intel and g++ if ( NOT WARNING_DISABLE AND ( WALBERLA_CXX_COMPILER_IS_GNU OR WALBERLA_CXX_COMPILER_IS_INTEL ) ) add_flag ( CMAKE_CXX_FLAGS "-Wall -Wconversion -Wshadow" ) @@ -290,7 +289,7 @@ endif() # C++ language features for NEC compiler if( WALBERLA_CXX_COMPILER_IS_NEC ) set( CMAKE_CXX14_STANDARD_COMPILE_OPTION "-Kcpp14" ) - add_flag ( CMAKE_CXX_FLAGS "${CMAKE_CXX14_STANDARD_COMPILE_OPTION} -Krtti -Kexceptions -size_t64 -Kgcc" ) + add_flag ( CMAKE_CXX_FLAGS "${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION} -Krtti -Kexceptions -size_t64 -Kgcc" ) add_flag ( CMAKE_CXX_FLAGS "-D__BIG_ENDIAN -D__BYTE_ORDER=__BIG_ENDIAN" ) add_flag ( CMAKE_CXX_FLAGS "-Tnoauto,used" ) add_flag ( CMAKE_EXE_LINKER_FLAGS "-Wl,-h,muldefs" ) @@ -442,19 +441,19 @@ endif() ############################################################################################################################ try_compile( WALBERLA_USE_STD_FILESYSTEM "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestStdFilesystem.cpp" - COMPILE_DEFINITIONS -DWALBERLA_USE_STD_FILESYSTEM ${CMAKE_CXX14_STANDARD_COMPILE_OPTION} ) + COMPILE_DEFINITIONS -DWALBERLA_USE_STD_FILESYSTEM ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION} ) if( WALBERLA_USE_STD_FILESYSTEM ) message( STATUS "Found std::filesystem") else() try_compile( WALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestStdFilesystem.cpp" - COMPILE_DEFINITIONS -DWALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM ${CMAKE_CXX14_STANDARD_COMPILE_OPTION} ) + COMPILE_DEFINITIONS -DWALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION} ) if( WALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM ) message( STATUS "Found std::experimental::filesystem") endif() if( NOT WALBERLA_CXX_COMPILER_IS_MSVC AND NOT WALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM ) unset( WALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM CACHE ) try_compile( WALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestStdFilesystem.cpp" - COMPILE_DEFINITIONS -DWALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM ${CMAKE_CXX14_STANDARD_COMPILE_OPTION} + COMPILE_DEFINITIONS -DWALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION} LINK_LIBRARIES stdc++fs ) if( WALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM ) message( STATUS "Found std::experimental::filesystem in libstdc++fs") @@ -464,7 +463,7 @@ else() if( NOT WALBERLA_CXX_COMPILER_IS_MSVC AND NOT WALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM ) unset( WALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM CACHE ) try_compile( WALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestStdFilesystem.cpp" - COMPILE_DEFINITIONS -DWALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM ${CMAKE_CXX14_STANDARD_COMPILE_OPTION} + COMPILE_DEFINITIONS -DWALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION} LINK_LIBRARIES c++experimental ) if( WALBERLA_USE_STD_EXPERIMENTAL_FILESYSTEM ) message( STATUS "Found std::experimental::filesystem in libc++experimental") @@ -474,29 +473,35 @@ else() endif() try_compile( WALBERLA_USE_STD_ANY "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestStdAny.cpp" - COMPILE_DEFINITIONS -DWALBERLA_USE_STD_ANY ${CMAKE_CXX14_STANDARD_COMPILE_OPTION} ) + COMPILE_DEFINITIONS -DWALBERLA_USE_STD_ANY ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION} ) if( WALBERLA_USE_STD_ANY ) message( STATUS "Found std::any") else() try_compile( WALBERLA_USE_STD_EXPERIMENTAL_ANY "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestStdAny.cpp" - COMPILE_DEFINITIONS -DWALBERLA_USE_STD_EXPERIMENTAL_ANY ${CMAKE_CXX14_STANDARD_COMPILE_OPTION} ) + COMPILE_DEFINITIONS -DWALBERLA_USE_STD_EXPERIMENTAL_ANY ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION} ) if( WALBERLA_USE_STD_EXPERIMENTAL_ANY ) message( STATUS "Found std::experimental::any") endif() endif() try_compile( WALBERLA_USE_STD_OPTIONAL "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestStdOptional.cpp" - COMPILE_DEFINITIONS -DWALBERLA_USE_STD_OPTIONAL ${CMAKE_CXX14_STANDARD_COMPILE_OPTION} ) + COMPILE_DEFINITIONS -DWALBERLA_USE_STD_OPTIONAL ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION} ) if( WALBERLA_USE_STD_OPTIONAL ) message( STATUS "Found std::optional") else() try_compile( WALBERLA_USE_STD_EXPERIMENTAL_OPTIONAL "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestStdOptional.cpp" - COMPILE_DEFINITIONS -DWALBERLA_USE_STD_EXPERIMENTAL_OPTIONAL ${CMAKE_CXX14_STANDARD_COMPILE_OPTION} ) + COMPILE_DEFINITIONS -DWALBERLA_USE_STD_EXPERIMENTAL_OPTIONAL ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION} ) if( WALBERLA_USE_STD_EXPERIMENTAL_OPTIONAL ) message( STATUS "Found std::experimental::optional") endif() endif() +try_compile( WALBERLA_USE_STD_VARIANT "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestStdVariant.cpp" + COMPILE_DEFINITIONS -DWALBERLA_USE_STD_VARIANT ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION} ) +if( WALBERLA_USE_STD_VARIANT ) + message( STATUS "Found std::variant") +endif() + ############################################################################################################################ @@ -1126,7 +1131,7 @@ if ( WALBERLA_BUILD_WITH_CUDA ) endif() if ( NOT "${CUDA_NVCC_FLAGS}" MATCHES "-std=" AND NOT WALBERLA_CXX_COMPILER_IS_MSVC ) - list ( APPEND CUDA_NVCC_FLAGS "-std=c++14" ) + list ( APPEND CUDA_NVCC_FLAGS "-std=c++${CMAKE_CXX_STANDARD}" ) endif () if(CMAKE_BUILD_TYPE MATCHES Debug) diff --git a/cmake/TestStdAny.cpp b/cmake/TestStdAny.cpp index 6b7e22269737d293cab1daba5d4030c186b5fcd8..6bcc880a6134bf1c0c538f6a32e92f87f6d1e8ea 100644 --- a/cmake/TestStdAny.cpp +++ b/cmake/TestStdAny.cpp @@ -8,9 +8,10 @@ int main() { #if defined(WALBERLA_USE_STD_ANY) auto a = std::any(42); + std::cout << std::any_cast<int>(a) << std::endl; #elif defined(WALBERLA_USE_STD_EXPERIMENTAL_ANY) auto a = std::experimental::any(42); -#endif std::cout << std::experimental::any_cast<int>(a) << std::endl; +#endif return 0; } diff --git a/cmake/TestStdVariant.cpp b/cmake/TestStdVariant.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be98d121ffcfbc96d73948fee5ed67e0f75e8256 --- /dev/null +++ b/cmake/TestStdVariant.cpp @@ -0,0 +1,7 @@ +#include <iostream> +#include <variant> + +int main() { + std::variant<int,float> a; + return 0; +} diff --git a/src/core/Variant.h b/src/core/Variant.h new file mode 100644 index 0000000000000000000000000000000000000000..7fe6d195afcacf49b0c1dea05d14edc61d0b408d --- /dev/null +++ b/src/core/Variant.h @@ -0,0 +1,58 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) OPTIONAL later version. +// +// waLBerla is distributed in the hope that it will be useful, but WITHOUT +// OPTIONAL WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Variant.h +//! \ingroup core +//! \author Stephan Seitz <stephan.seitz@fau.de> +// +//====================================================================================================================== + +#pragma once + + +#if defined(WALBERLA_USE_STD_VARIANT) +#include <variant> +#else +#include <boost/variant.hpp> +#endif + + + +namespace walberla +{ + +#if defined(WALBERLA_USE_STD_VARIANT) +using std::variant; +using std::visit; +using std::get; +using std::holds_alternative; +using std::bad_variant_access; +#else +using boost::variant; +using boost::get; +template <class T, class... Types> +constexpr bool holds_alternative( const boost::variant<Types...>& v ) noexcept +{ + return v.type() == typeid( T ); +} +using bad_variant_access = boost::bad_get; +template<typename Visitor, typename... Variant> +decltype( auto ) visit( Visitor&& visitor, Variant&& ... variant ) +{ + return boost::apply_visitor( visitor, variant... ); +} +#endif + +} diff --git a/src/waLBerlaDefinitions.in.h b/src/waLBerlaDefinitions.in.h index bb9b6d029d80340f34342401a23d2f13e2356b7d..654eb55ab235a5a583099cdbcfedb46e1844297a 100644 --- a/src/waLBerlaDefinitions.in.h +++ b/src/waLBerlaDefinitions.in.h @@ -53,6 +53,7 @@ #cmakedefine WALBERLA_USE_STD_ANY #cmakedefine WALBERLA_USE_STD_EXPERIMENTAL_OPTIONAL #cmakedefine WALBERLA_USE_STD_OPTIONAL +#cmakedefine WALBERLA_USE_STD_VARIANT #cmakedefine WALBERLA_BUILD_WITH_BACKTRACE #ifdef WALBERLA_BUILD_WITH_BACKTRACE #define WALBERLA_BACKTRACE_HEADER "${Backtrace_HEADER}" diff --git a/tests/core/CMakeLists.txt b/tests/core/CMakeLists.txt index 185fc8be096a4d357d6a6f64225d4cdc6ffe637c..4d58647b8a563af3a86f01183f226136f835427f 100644 --- a/tests/core/CMakeLists.txt +++ b/tests/core/CMakeLists.txt @@ -209,6 +209,11 @@ waLBerla_execute_test( NAME UNIQUEID PROCESSES 4) waLBerla_compile_test( FILES VersionTest.cpp ) waLBerla_execute_test( NAME VersionTest ) +if( WALBERLA_BUILD_WITH_BOOST OR WALBERLA_USE_STD_VARIANT ) + waLBerla_compile_test( FILES VariantTest ) + waLBerla_execute_test( NAME VariantTest ) +endif() + ################## # load_balancing # ################## diff --git a/tests/core/VariantTest.cpp b/tests/core/VariantTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a879b5b98a7020a93f51bcb20ea1baf952a97eba --- /dev/null +++ b/tests/core/VariantTest.cpp @@ -0,0 +1,81 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file VariantTest.cpp +//! \ingroup core +//! \author Step +//! \brief Test if there are no typos in the collective header files "all.h" +// +//====================================================================================================================== + +#include "core/Variant.h" +#include "core/debug/all.h" + +#include <string> +#include <cassert> +#include <iostream> +#include <vector> + +using namespace std::literals; // C++ 14 +using var_t = walberla::variant<int, long, double, std::string>; + +int main( int /*argc*/, char** /*argv*/ ) +{ + walberla::debug::enterTestMode(); + + + + // Example from: https://en.cppreference.com/w/cpp/utility/variant (license (CC-BY-SA) and GPL) + walberla::variant<int, float> v, w; + v = 12; // v contains int + int i = walberla::get<int>( v ); +#ifdef WALBERLA_USE_STD_VARIANT + WALBERLA_CHECK( i == 12 ); // boost::variant cannot use == with variant and type +#endif + WALBERLA_CHECK( 0 == 12 - i ); + w = walberla::get<int>( v ); + w = v; +#ifdef WALBERLA_USE_STD_VARIANT + WALBERLA_CHECK( w == 12 ); // boost::variant cannot use == with variant and type +#endif + WALBERLA_CHECK( 0 == 12 - i ); + + // walberla::get<double>(v); // error: no double in [int, float] + // walberla::get<3>(v); // error: valid index values are 0 and 1 + + try { + walberla::get<float>( w ); // w contains int, not float: will throw + } catch ( const walberla::bad_variant_access& ) {} + + walberla::variant<std::string> x( "abc" ); // converting constructors work when unambiguous + x = "def"; // converting assignment also works when unambiguous + + std::cout << "hallo" << std::endl; + walberla::variant<std::string, bool> y( "abc" ); // casts to bool when passed a char const * + std::cout << "eoo" << std::endl; + WALBERLA_CHECK( walberla::holds_alternative<bool>( y ) ); // succeeds + y = "xyz"s; + WALBERLA_CHECK( walberla::holds_alternative<std::string>( y ) ); //succeeds + + std::cout << "bye" << std::endl; + std::vector<var_t> vec {10, 15l, 1.5, "hello"}; + + for ( auto& z : vec ) { + // 1. void visitor, only called for side-effects (here, for I/O) + walberla::visit( []( auto && arg ) {std::cout << arg;}, z ); + } + + return 0; +}