mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 14:45:12 +00:00
Add support for boost::variant in C++11 mode
In C++11 mode, `boost::apply_visitor` requires an explicit `result_type`. This also adds optional tests for `boost::variant` in C++11/14, if boost is available. In C++17 mode, `std::variant` is tested instead.
This commit is contained in:
parent
e06077bf47
commit
7918bcc95b
@ -28,8 +28,12 @@ matrix:
|
|||||||
install:
|
install:
|
||||||
- ps: |
|
- ps: |
|
||||||
if ($env:PLATFORM -eq "x64") { $env:CMAKE_ARCH = "x64" }
|
if ($env:PLATFORM -eq "x64") { $env:CMAKE_ARCH = "x64" }
|
||||||
if ($env:APPVEYOR_JOB_NAME -like "*Visual Studio 2017*") { $env:CMAKE_GENERATOR = "Visual Studio 15 2017" }
|
if ($env:APPVEYOR_JOB_NAME -like "*Visual Studio 2017*") {
|
||||||
else { $env:CMAKE_GENERATOR = "Visual Studio 14 2015" }
|
$env:CMAKE_GENERATOR = "Visual Studio 15 2017"
|
||||||
|
$env:CMAKE_INCLUDE_PATH = "C:\Libraries\boost_1_64_0"
|
||||||
|
} else {
|
||||||
|
$env:CMAKE_GENERATOR = "Visual Studio 14 2015"
|
||||||
|
}
|
||||||
if ($env:PYTHON) {
|
if ($env:PYTHON) {
|
||||||
if ($env:PLATFORM -eq "x64") { $env:PYTHON = "$env:PYTHON-x64" }
|
if ($env:PLATFORM -eq "x64") { $env:PYTHON = "$env:PYTHON-x64" }
|
||||||
$env:PATH = "C:\Python$env:PYTHON\;C:\Python$env:PYTHON\Scripts\;$env:PATH"
|
$env:PATH = "C:\Python$env:PYTHON\;C:\Python$env:PYTHON\Scripts\;$env:PATH"
|
||||||
@ -45,7 +49,7 @@ install:
|
|||||||
- ps: |
|
- ps: |
|
||||||
Start-FileDownload 'http://bitbucket.org/eigen/eigen/get/3.3.3.zip'
|
Start-FileDownload 'http://bitbucket.org/eigen/eigen/get/3.3.3.zip'
|
||||||
7z x 3.3.3.zip -y > $null
|
7z x 3.3.3.zip -y > $null
|
||||||
$env:CMAKE_INCLUDE_PATH = "eigen-eigen-67e894c6cd8f"
|
$env:CMAKE_INCLUDE_PATH = "eigen-eigen-67e894c6cd8f;$env:CMAKE_INCLUDE_PATH"
|
||||||
build_script:
|
build_script:
|
||||||
- cmake -G "%CMAKE_GENERATOR%" -A "%CMAKE_ARCH%"
|
- cmake -G "%CMAKE_GENERATOR%" -A "%CMAKE_ARCH%"
|
||||||
-DPYBIND11_CPP_STANDARD=/std:c++%CPP%
|
-DPYBIND11_CPP_STANDARD=/std:c++%CPP%
|
||||||
|
@ -150,7 +150,7 @@ install:
|
|||||||
$SCRIPT_RUN_PREFIX sh -c "for s in 0 15; do sleep \$s; \
|
$SCRIPT_RUN_PREFIX sh -c "for s in 0 15; do sleep \$s; \
|
||||||
apt-get -qy --no-install-recommends install \
|
apt-get -qy --no-install-recommends install \
|
||||||
$PY_DEBUG python$PYTHON-dev python$PY-pytest python$PY-scipy \
|
$PY_DEBUG python$PYTHON-dev python$PY-pytest python$PY-scipy \
|
||||||
libeigen3-dev cmake make ${COMPILER_PACKAGES} && break; done"
|
libeigen3-dev libboost-dev cmake make ${COMPILER_PACKAGES} && break; done"
|
||||||
else
|
else
|
||||||
|
|
||||||
if [ "$CLANG" = "4.0" ]; then
|
if [ "$CLANG" = "4.0" ]; then
|
||||||
|
@ -60,8 +60,7 @@ for custom variant types:
|
|||||||
template <>
|
template <>
|
||||||
struct visit_helper<boost::variant> {
|
struct visit_helper<boost::variant> {
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
static auto call(Args &&...args)
|
static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) {
|
||||||
-> decltype(boost::apply_visitor(args...)) {
|
|
||||||
return boost::apply_visitor(args...);
|
return boost::apply_visitor(args...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -71,6 +70,13 @@ The ``visit_helper`` specialization is not required if your ``name::variant`` pr
|
|||||||
a ``name::visit()`` function. For any other function name, the specialization must be
|
a ``name::visit()`` function. For any other function name, the specialization must be
|
||||||
included to tell pybind11 how to visit the variant.
|
included to tell pybind11 how to visit the variant.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
pybind11 only supports the modern implementation of ``boost::variant``
|
||||||
|
which makes use of variadic templates. This requires Boost 1.56 or newer.
|
||||||
|
Additionally, on Windows, MSVC 2017 is required because ``boost::variant``
|
||||||
|
falls back to the old non-variadic implementation on MSVC 2015.
|
||||||
|
|
||||||
.. _opaque:
|
.. _opaque:
|
||||||
|
|
||||||
Making opaque types
|
Making opaque types
|
||||||
|
@ -292,8 +292,10 @@ struct variant_caster_visitor {
|
|||||||
return_value_policy policy;
|
return_value_policy policy;
|
||||||
handle parent;
|
handle parent;
|
||||||
|
|
||||||
|
using result_type = handle; // required by boost::variant in C++11
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
handle operator()(T &&src) const {
|
result_type operator()(T &&src) const {
|
||||||
return make_caster<T>::cast(std::forward<T>(src), policy, parent);
|
return make_caster<T>::cast(std::forward<T>(src), policy, parent);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -112,6 +112,9 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Optional dependency for some tests
|
||||||
|
find_package(Boost)
|
||||||
|
|
||||||
# Compile with compiler warnings turned on
|
# Compile with compiler warnings turned on
|
||||||
function(pybind11_enable_warnings target_name)
|
function(pybind11_enable_warnings target_name)
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
@ -141,37 +144,40 @@ foreach(t ${PYBIND11_CROSS_MODULE_TESTS})
|
|||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
set(testdir ${CMAKE_CURRENT_SOURCE_DIR})
|
set(testdir ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
foreach(tgt ${test_targets})
|
foreach(target ${test_targets})
|
||||||
set(test_files ${PYBIND11_TEST_FILES})
|
set(test_files ${PYBIND11_TEST_FILES})
|
||||||
if(NOT tgt STREQUAL "pybind11_tests")
|
if(NOT target STREQUAL "pybind11_tests")
|
||||||
set(test_files "")
|
set(test_files "")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Create the binding library
|
# Create the binding library
|
||||||
pybind11_add_module(${tgt} THIN_LTO ${tgt}.cpp
|
pybind11_add_module(${target} THIN_LTO ${target}.cpp ${test_files} ${PYBIND11_HEADERS})
|
||||||
${test_files} ${PYBIND11_HEADERS})
|
pybind11_enable_warnings(${target})
|
||||||
|
|
||||||
pybind11_enable_warnings(${tgt})
|
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
target_compile_options(${tgt} PRIVATE /utf-8)
|
target_compile_options(${target} PRIVATE /utf-8)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(EIGEN3_FOUND)
|
if(EIGEN3_FOUND)
|
||||||
if (PYBIND11_EIGEN_VIA_TARGET)
|
if (PYBIND11_EIGEN_VIA_TARGET)
|
||||||
target_link_libraries(${tgt} PRIVATE Eigen3::Eigen)
|
target_link_libraries(${target} PRIVATE Eigen3::Eigen)
|
||||||
else()
|
else()
|
||||||
target_include_directories(${tgt} PRIVATE ${EIGEN3_INCLUDE_DIR})
|
target_include_directories(${target} PRIVATE ${EIGEN3_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
target_compile_definitions(${tgt} PRIVATE -DPYBIND11_TEST_EIGEN)
|
target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_EIGEN)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(Boost_FOUND)
|
||||||
|
target_include_directories(${target} PRIVATE ${Boost_INCLUDE_DIRS})
|
||||||
|
target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Always write the output file directly into the 'tests' directory (even on MSVC)
|
# Always write the output file directly into the 'tests' directory (even on MSVC)
|
||||||
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
||||||
set_target_properties(${tgt} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${testdir})
|
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${testdir})
|
||||||
foreach(config ${CMAKE_CONFIGURATION_TYPES})
|
foreach(config ${CMAKE_CONFIGURATION_TYPES})
|
||||||
string(TOUPPER ${config} config)
|
string(TOUPPER ${config} config)
|
||||||
set_target_properties(${tgt} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} ${testdir})
|
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} ${testdir})
|
||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
@ -10,6 +10,27 @@
|
|||||||
#include "pybind11_tests.h"
|
#include "pybind11_tests.h"
|
||||||
#include <pybind11/stl.h>
|
#include <pybind11/stl.h>
|
||||||
|
|
||||||
|
// Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14
|
||||||
|
#if PYBIND11_HAS_VARIANT
|
||||||
|
using std::variant;
|
||||||
|
#elif PYBIND11_TEST_BOOST
|
||||||
|
# include <boost/variant.hpp>
|
||||||
|
# define PYBIND11_HAS_VARIANT 1
|
||||||
|
using boost::variant;
|
||||||
|
|
||||||
|
namespace pybind11 { namespace detail {
|
||||||
|
template <typename... Ts>
|
||||||
|
struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct visit_helper<boost::variant> {
|
||||||
|
template <typename... Args>
|
||||||
|
static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) {
|
||||||
|
return boost::apply_visitor(args...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}} // namespace pybind11::detail
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Issue #528: templated constructor
|
/// Issue #528: templated constructor
|
||||||
struct TplCtorClass {
|
struct TplCtorClass {
|
||||||
@ -162,22 +183,27 @@ TEST_SUBMODULE(stl, m) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PYBIND11_HAS_VARIANT
|
#ifdef PYBIND11_HAS_VARIANT
|
||||||
|
static_assert(std::is_same<py::detail::variant_caster_visitor::result_type, py::handle>::value,
|
||||||
|
"visitor::result_type is required by boost::variant in C++11 mode");
|
||||||
|
|
||||||
struct visitor {
|
struct visitor {
|
||||||
const char *operator()(int) { return "int"; }
|
using result_type = const char *;
|
||||||
const char *operator()(std::string) { return "std::string"; }
|
|
||||||
const char *operator()(double) { return "double"; }
|
result_type operator()(int) { return "int"; }
|
||||||
const char *operator()(std::nullptr_t) { return "std::nullptr_t"; }
|
result_type operator()(std::string) { return "std::string"; }
|
||||||
|
result_type operator()(double) { return "double"; }
|
||||||
|
result_type operator()(std::nullptr_t) { return "std::nullptr_t"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// test_variant
|
// test_variant
|
||||||
m.def("load_variant", [](std::variant<int, std::string, double, std::nullptr_t> v) {
|
m.def("load_variant", [](variant<int, std::string, double, std::nullptr_t> v) {
|
||||||
return std::visit(visitor(), v);
|
return py::detail::visit_helper<variant>::call(visitor(), v);
|
||||||
});
|
});
|
||||||
m.def("load_variant_2pass", [](std::variant<double, int> v) {
|
m.def("load_variant_2pass", [](variant<double, int> v) {
|
||||||
return std::visit(visitor(), v);
|
return py::detail::visit_helper<variant>::call(visitor(), v);
|
||||||
});
|
});
|
||||||
m.def("cast_variant", []() {
|
m.def("cast_variant", []() {
|
||||||
using V = std::variant<int, std::string>;
|
using V = variant<int, std::string>;
|
||||||
return py::make_tuple(V(5), V("Hello"));
|
return py::make_tuple(V(5), V("Hello"));
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user