mirror of
https://github.com/opencv/opencv.git
synced 2024-11-28 05:06:29 +08:00
Merge pull request #20039 from sivanov-work:gapi_empty_input
G-API: Implement variant visit() * Add variant visitor, use visitor for check compile args * Fix GAPI UT: variant *compiler * Aling apply_visior with std, fix indentations * Fix compilation (included compiler_hints.hpp) * Fix compilation (due gapi standalone) * Fix compilation2 (Docs) * Add Lambdas overload, Refactor visit() * Add ReturnType auto deduction * Fix comilation * Fix compilation * Fix warnings * Try to fix MSVC14 * Fix docs * Try fix Win compile * Fix Docs again * Revert GAPI empty input fix * Apply comment for `tuple_element` * Add std::decay for std::base_of to work arounf armv7 problem * Apply review comments * Apply review comments: added comment & removed unused args * Fix docs compilation
This commit is contained in:
parent
ed2a698392
commit
c0f63eb21f
@ -43,19 +43,6 @@ namespace detail
|
||||
GOPAQUE, // a cv::GOpaqueU (note - exactly GOpaqueU, not GOpaque<T>!)
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr const char* meta_to_string() noexcept;
|
||||
template<>
|
||||
constexpr const char* meta_to_string<cv::GMatDesc>() noexcept { return "GMatDesc"; }
|
||||
template<>
|
||||
constexpr const char* meta_to_string<cv::GScalarDesc>() noexcept { return "GScalarDesc"; }
|
||||
template<>
|
||||
constexpr const char* meta_to_string<cv::GArrayDesc>() noexcept { return "GArrayDesc"; }
|
||||
template<>
|
||||
constexpr const char* meta_to_string<cv::GOpaqueDesc>() noexcept { return "GOpaqueDesc"; }
|
||||
template<>
|
||||
constexpr const char* meta_to_string<cv::GFrameDesc>() noexcept { return "GFrameDesc";}
|
||||
|
||||
// Describe G-API types (G-types) with traits. Mostly used by
|
||||
// cv::GArg to store meta information about types passed into
|
||||
// operation arguments. Please note that cv::GComputation is
|
||||
|
@ -35,7 +35,6 @@ namespace detail
|
||||
template<> struct ProtoToMeta<cv::GScalar> { using type = cv::GScalarDesc; };
|
||||
template<typename U> struct ProtoToMeta<cv::GArray<U> > { using type = cv::GArrayDesc; };
|
||||
template<typename U> struct ProtoToMeta<cv::GOpaque<U> > { using type = cv::GOpaqueDesc; };
|
||||
template<> struct ProtoToMeta<cv::GFrame> { using type = cv::GFrameDesc; };
|
||||
template<typename T> using ProtoToMetaT = typename ProtoToMeta<T>::type;
|
||||
|
||||
//workaround for MSVC 19.0 bug
|
||||
|
@ -117,6 +117,43 @@ namespace detail
|
||||
static type get(std::tuple<Objs...>&& objs) { return std::forward<std::tuple<Objs...>>(objs); }
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
namespace util
|
||||
{
|
||||
template<typename ...L>
|
||||
struct overload_lamba_set;
|
||||
|
||||
template<typename L1>
|
||||
struct overload_lamba_set<L1> : public L1
|
||||
{
|
||||
overload_lamba_set(L1&& lambda) : L1(std::move(lambda)) {}
|
||||
overload_lamba_set(const L1& lambda) : L1(lambda) {}
|
||||
|
||||
using L1::operator();
|
||||
};
|
||||
|
||||
template<typename L1, typename ...L>
|
||||
struct overload_lamba_set<L1, L...> : public L1, public overload_lamba_set<L...>
|
||||
{
|
||||
using base_type = overload_lamba_set<L...>;
|
||||
overload_lamba_set(L1 &&lambda1, L&& ...lambdas):
|
||||
L1(std::move(lambda1)),
|
||||
base_type(std::forward<L>(lambdas)...) {}
|
||||
|
||||
overload_lamba_set(const L1 &lambda1, L&& ...lambdas):
|
||||
L1(lambda1),
|
||||
base_type(std::forward<L>(lambdas)...) {}
|
||||
|
||||
using L1::operator();
|
||||
using base_type::operator();
|
||||
};
|
||||
|
||||
template<typename... L>
|
||||
overload_lamba_set<L...> overload_lambdas(L&& ...lambdas)
|
||||
{
|
||||
return overload_lamba_set<L...>(std::forward<L>(lambdas)...);
|
||||
}
|
||||
}
|
||||
} // namespace cv
|
||||
|
||||
// \endcond
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
|
||||
#include <opencv2/gapi/util/compiler_hints.hpp>
|
||||
#include <opencv2/gapi/util/throw.hpp>
|
||||
#include <opencv2/gapi/util/util.hpp> // max_of_t
|
||||
#include <opencv2/gapi/util/type_traits.hpp>
|
||||
@ -44,6 +45,12 @@ namespace util
|
||||
static const constexpr std::size_t value = detail::type_list_index_helper<0, Target, Types...>::value;
|
||||
};
|
||||
|
||||
template<std::size_t Index, class... Types >
|
||||
struct type_list_element
|
||||
{
|
||||
using type = typename std::tuple_element<Index, std::tuple<Types...> >::type;
|
||||
};
|
||||
|
||||
class bad_variant_access: public std::exception
|
||||
{
|
||||
public:
|
||||
@ -233,9 +240,87 @@ namespace util
|
||||
template<typename T, typename... Types>
|
||||
const T& get(const util::variant<Types...> &v);
|
||||
|
||||
template<std::size_t Index, typename... Types>
|
||||
typename util::type_list_element<Index, Types...>::type& get(util::variant<Types...> &v);
|
||||
|
||||
template<std::size_t Index, typename... Types>
|
||||
const typename util::type_list_element<Index, Types...>::type& get(const util::variant<Types...> &v);
|
||||
|
||||
template<typename T, typename... Types>
|
||||
bool holds_alternative(const util::variant<Types...> &v) noexcept;
|
||||
|
||||
|
||||
// Visitor
|
||||
namespace detail
|
||||
{
|
||||
struct visitor_interface {};
|
||||
|
||||
// Class `visitor_return_type_deduction_helper`
|
||||
// introduces solution for deduction `return_type` in `visit` function in common way
|
||||
// for both Lambda and class Visitor and keep one interface invocation point: `visit` only
|
||||
// his helper class is required to unify return_type deduction mechanism because
|
||||
// for Lambda it is possible to take type of `decltype(visitor(get<0>(var)))`
|
||||
// but for class Visitor there is no operator() in base case,
|
||||
// because it provides `operator() (std::size_t index, ...)`
|
||||
// So `visitor_return_type_deduction_helper` expose `operator()`
|
||||
// uses only for class Visitor only for deduction `return type` in visit()
|
||||
template<typename R>
|
||||
struct visitor_return_type_deduction_helper
|
||||
{
|
||||
using return_type = R;
|
||||
|
||||
// to be used in Lambda return type deduction context only
|
||||
template<typename T>
|
||||
return_type operator() (T&&);
|
||||
};
|
||||
}
|
||||
|
||||
// Special purpose `static_visitor` can receive additional arguments
|
||||
template<typename R, typename Impl>
|
||||
struct static_visitor : public detail::visitor_interface,
|
||||
public detail::visitor_return_type_deduction_helper<R> {
|
||||
|
||||
// assign responsibility for return type deduction to helper class
|
||||
using return_type = typename detail::visitor_return_type_deduction_helper<R>::return_type;
|
||||
using detail::visitor_return_type_deduction_helper<R>::operator();
|
||||
friend Impl;
|
||||
|
||||
template<typename VariantValue, typename ...Args>
|
||||
return_type operator() (std::size_t index, VariantValue&& value, Args&& ...args)
|
||||
{
|
||||
suppress_unused_warning(index);
|
||||
return static_cast<Impl*>(this)-> visit(
|
||||
std::forward<VariantValue>(value),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
// Special purpose `static_indexed_visitor` can receive additional arguments
|
||||
// And make forwarding current variant index as runtime function argument to its `Impl`
|
||||
template<typename R, typename Impl>
|
||||
struct static_indexed_visitor : public detail::visitor_interface,
|
||||
public detail::visitor_return_type_deduction_helper<R> {
|
||||
|
||||
// assign responsibility for return type deduction to helper class
|
||||
using return_type = typename detail::visitor_return_type_deduction_helper<R>::return_type;
|
||||
using detail::visitor_return_type_deduction_helper<R>::operator();
|
||||
friend Impl;
|
||||
|
||||
template<typename VariantValue, typename ...Args>
|
||||
return_type operator() (std::size_t Index, VariantValue&& value, Args&& ...args)
|
||||
{
|
||||
return static_cast<Impl*>(this)-> visit(Index,
|
||||
std::forward<VariantValue>(value),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct variant_size;
|
||||
|
||||
template <class... Types>
|
||||
struct variant_size<util::variant<Types...>>
|
||||
: std::integral_constant<std::size_t, sizeof...(Types)> { };
|
||||
// FIXME: T&&, const TT&& versions.
|
||||
|
||||
// Implementation //////////////////////////////////////////////////////////
|
||||
@ -402,6 +487,22 @@ namespace util
|
||||
throw_error(bad_variant_access());
|
||||
}
|
||||
|
||||
template<std::size_t Index, typename... Types>
|
||||
typename util::type_list_element<Index, Types...>::type& get(util::variant<Types...> &v)
|
||||
{
|
||||
using ReturnType = typename util::type_list_element<Index, Types...>::type;
|
||||
return const_cast<ReturnType&>(get<Index, Types...>(static_cast<const util::variant<Types...> &>(v)));
|
||||
}
|
||||
|
||||
template<std::size_t Index, typename... Types>
|
||||
const typename util::type_list_element<Index, Types...>::type& get(const util::variant<Types...> &v)
|
||||
{
|
||||
static_assert(Index < sizeof...(Types),
|
||||
"`Index` it out of bound of `util::variant` type list");
|
||||
using ReturnType = typename util::type_list_element<Index, Types...>::type;
|
||||
return get<ReturnType>(v);
|
||||
}
|
||||
|
||||
template<typename T, typename... Types>
|
||||
bool holds_alternative(const util::variant<Types...> &v) noexcept
|
||||
{
|
||||
@ -428,7 +529,130 @@ namespace util
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
} // namespace cv
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// terminate recursion implementation for `non-void` ReturnType
|
||||
template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
|
||||
typename Visitor, typename Variant, typename... VisitorArgs>
|
||||
ReturnType apply_visitor_impl(Visitor&&, Variant&,
|
||||
std::true_type, std::false_type,
|
||||
VisitorArgs&& ...)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
// terminate recursion implementation for `void` ReturnType
|
||||
template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
|
||||
typename Visitor, typename Variant, typename... VisitorArgs>
|
||||
void apply_visitor_impl(Visitor&&, Variant&,
|
||||
std::true_type, std::true_type,
|
||||
VisitorArgs&& ...)
|
||||
{
|
||||
}
|
||||
|
||||
// Intermediate resursion processor for Lambda Visitors
|
||||
template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
|
||||
typename Visitor, typename Variant, bool no_return_value, typename... VisitorArgs>
|
||||
typename std::enable_if<!std::is_base_of<visitor_interface, typename std::decay<Visitor>::type>::value, ReturnType>::type
|
||||
apply_visitor_impl(Visitor&& visitor, Variant&& v, std::false_type not_processed,
|
||||
std::integral_constant<bool, no_return_value> should_no_return,
|
||||
VisitorArgs&& ...args)
|
||||
{
|
||||
static_assert(std::is_same<ReturnType, decltype(visitor(get<CurIndex>(v)))>::value,
|
||||
"Different `ReturnType`s detected! All `Visitor::visit` or `overload_lamba_set`"
|
||||
" must return the same type");
|
||||
suppress_unused_warning(not_processed);
|
||||
if (v.index() == CurIndex)
|
||||
{
|
||||
return visitor.operator()(get<CurIndex>(v), std::forward<VisitorArgs>(args)... );
|
||||
}
|
||||
|
||||
using is_variant_processed_t = std::integral_constant<bool, CurIndex + 1 >= ElemCount>;
|
||||
return apply_visitor_impl<ReturnType, CurIndex +1, ElemCount>(
|
||||
std::forward<Visitor>(visitor),
|
||||
std::forward<Variant>(v),
|
||||
is_variant_processed_t{},
|
||||
should_no_return,
|
||||
std::forward<VisitorArgs>(args)...);
|
||||
}
|
||||
|
||||
//Visual Studio 2014 compilation fix: cast visitor to base class before invoke operator()
|
||||
template<std::size_t CurIndex, typename ReturnType, typename Visitor, class Value, typename... VisitorArgs>
|
||||
typename std::enable_if<std::is_base_of<static_visitor<ReturnType, typename std::decay<Visitor>::type>,
|
||||
typename std::decay<Visitor>::type>::value, ReturnType>::type
|
||||
invoke_class_visitor(Visitor& visitor, Value&& v, VisitorArgs&&...args)
|
||||
{
|
||||
return static_cast<static_visitor<ReturnType, typename std::decay<Visitor>::type>&>(visitor).operator() (CurIndex, std::forward<Value>(v), std::forward<VisitorArgs>(args)... );
|
||||
}
|
||||
|
||||
//Visual Studio 2014 compilation fix: cast visitor to base class before invoke operator()
|
||||
template<std::size_t CurIndex, typename ReturnType, typename Visitor, class Value, typename... VisitorArgs>
|
||||
typename std::enable_if<std::is_base_of<static_indexed_visitor<ReturnType, typename std::decay<Visitor>::type>,
|
||||
typename std::decay<Visitor>::type>::value, ReturnType>::type
|
||||
invoke_class_visitor(Visitor& visitor, Value&& v, VisitorArgs&&...args)
|
||||
{
|
||||
return static_cast<static_indexed_visitor<ReturnType, typename std::decay<Visitor>::type>&>(visitor).operator() (CurIndex, std::forward<Value>(v), std::forward<VisitorArgs>(args)... );
|
||||
}
|
||||
|
||||
// Intermediate recursion processor for special case `visitor_interface` derived Visitors
|
||||
template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
|
||||
typename Visitor, typename Variant, bool no_return_value, typename... VisitorArgs>
|
||||
typename std::enable_if<std::is_base_of<visitor_interface, typename std::decay<Visitor>::type>::value, ReturnType>::type
|
||||
apply_visitor_impl(Visitor&& visitor, Variant&& v, std::false_type not_processed,
|
||||
std::integral_constant<bool, no_return_value> should_no_return,
|
||||
VisitorArgs&& ...args)
|
||||
{
|
||||
static_assert(std::is_same<ReturnType, decltype(visitor(get<CurIndex>(v)))>::value,
|
||||
"Different `ReturnType`s detected! All `Visitor::visit` or `overload_lamba_set`"
|
||||
" must return the same type");
|
||||
suppress_unused_warning(not_processed);
|
||||
if (v.index() == CurIndex)
|
||||
{
|
||||
return invoke_class_visitor<CurIndex, ReturnType>(visitor, get<CurIndex>(v), std::forward<VisitorArgs>(args)... );
|
||||
}
|
||||
|
||||
using is_variant_processed_t = std::integral_constant<bool, CurIndex + 1 >= ElemCount>;
|
||||
return apply_visitor_impl<ReturnType, CurIndex +1, ElemCount>(
|
||||
std::forward<Visitor>(visitor),
|
||||
std::forward<Variant>(v),
|
||||
is_variant_processed_t{},
|
||||
should_no_return,
|
||||
std::forward<VisitorArgs>(args)...);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template<typename Visitor, typename Variant, typename... VisitorArg>
|
||||
auto visit(Visitor &visitor, const Variant& var, VisitorArg &&...args) -> decltype(visitor(get<0>(var)))
|
||||
{
|
||||
constexpr std::size_t varsize = util::variant_size<Variant>::value;
|
||||
static_assert(varsize != 0, "utils::variant must contains one type at least ");
|
||||
using is_variant_processed_t = std::false_type;
|
||||
|
||||
using ReturnType = decltype(visitor(get<0>(var)));
|
||||
using return_t = std::is_same<ReturnType, void>;
|
||||
return detail::apply_visitor_impl<ReturnType, 0, varsize, Visitor>(
|
||||
std::forward<Visitor>(visitor),
|
||||
var, is_variant_processed_t{},
|
||||
return_t{},
|
||||
std::forward<VisitorArg>(args)...);
|
||||
}
|
||||
|
||||
template<typename Visitor, typename Variant>
|
||||
auto visit(Visitor&& visitor, const Variant& var) -> decltype(visitor(get<0>(var)))
|
||||
{
|
||||
constexpr std::size_t varsize = util::variant_size<Variant>::value;
|
||||
static_assert(varsize != 0, "utils::variant must contains one type at least ");
|
||||
using is_variant_processed_t = std::false_type;
|
||||
|
||||
using ReturnType = decltype(visitor(get<0>(var)));
|
||||
using return_t = std::is_same<ReturnType, void>;
|
||||
return detail::apply_visitor_impl<ReturnType, 0, varsize, Visitor>(
|
||||
std::forward<Visitor>(visitor),
|
||||
var, is_variant_processed_t{},
|
||||
return_t{});
|
||||
}
|
||||
} // namespace util
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_UTIL_VARIANT_HPP
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
#include "api/gorigin.hpp"
|
||||
#include "api/gproto_priv.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
// FIXME: it should be a visitor!
|
||||
// FIXME: Reimplement with traits?
|
||||
@ -277,13 +276,9 @@ void cv::validate_input_arg(const GRunArg& arg)
|
||||
|
||||
void cv::validate_input_args(const GRunArgs& args)
|
||||
{
|
||||
GAPI_LOG_DEBUG(nullptr, "Total count: " << args.size());
|
||||
size_t index = 0;
|
||||
for (const auto& arg : args)
|
||||
{
|
||||
GAPI_LOG_DEBUG(nullptr, "Process index: " << index);
|
||||
validate_input_arg(arg);
|
||||
index ++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -354,6 +354,20 @@ TEST(Variant, Get)
|
||||
EXPECT_THROW(util::get<int>(cv2), util::bad_variant_access);
|
||||
}
|
||||
|
||||
TEST(Variant, GetIndexed)
|
||||
{
|
||||
const TestVar cv(42);
|
||||
|
||||
// Test const& get()
|
||||
EXPECT_EQ(42, util::get<0>(cv));
|
||||
EXPECT_THROW(util::get<1>(cv), util::bad_variant_access);
|
||||
|
||||
// Test &get
|
||||
TestVar cv2(std::string("42"));
|
||||
EXPECT_EQ("42", util::get<1>(cv2));
|
||||
EXPECT_THROW(util::get<0>(cv2), util::bad_variant_access);
|
||||
}
|
||||
|
||||
TEST(Variant, GetWrite)
|
||||
{
|
||||
util::variant<int, std::string> v(42);
|
||||
@ -486,4 +500,240 @@ TEST(Variant, EXT_IndexOf)
|
||||
static_assert(6u == V::index_of<MyClass>(), "Index is incorrect");
|
||||
}
|
||||
|
||||
namespace test_validation
|
||||
{
|
||||
struct MyType
|
||||
{
|
||||
friend std::ostream& operator<<(std::ostream& out, const MyType& src)
|
||||
{
|
||||
return out << "MyType"; (void) src;
|
||||
}
|
||||
};
|
||||
class MyClass
|
||||
{
|
||||
friend std::ostream& operator<<(std::ostream& out, const MyClass& src)
|
||||
{
|
||||
return out << "MyClass"; (void) src;
|
||||
}
|
||||
};
|
||||
|
||||
struct MyBoolParamIndexedVisitor : cv::util::static_indexed_visitor<bool, MyBoolParamIndexedVisitor>
|
||||
{
|
||||
MyBoolParamIndexedVisitor(std::ostream &output) : out(output) {}
|
||||
|
||||
template<class Type>
|
||||
bool visit(std::size_t index, Type val, int check)
|
||||
{
|
||||
bool result = false;
|
||||
out << index << ":" << val <<",";
|
||||
if(std::is_same<Type, int>::value)
|
||||
{
|
||||
result = !memcmp(&val, &check, sizeof(int));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::ostream &out;
|
||||
};
|
||||
|
||||
struct MyBoolNoParamNonIndexedVisitor : cv::util::static_indexed_visitor<bool, MyBoolNoParamNonIndexedVisitor>
|
||||
{
|
||||
MyBoolNoParamNonIndexedVisitor(std::ostream &output) : out(output) {}
|
||||
|
||||
template<class Type>
|
||||
bool visit(std::size_t index, Type val)
|
||||
{
|
||||
out << index << ":" << val <<",";
|
||||
return true;
|
||||
}
|
||||
std::ostream &out;
|
||||
};
|
||||
|
||||
|
||||
struct MyVoidNoParamNonIndexedVisitor : cv::util::static_visitor<void, MyVoidNoParamNonIndexedVisitor>
|
||||
{
|
||||
MyVoidNoParamNonIndexedVisitor(std::ostream &output) : out(output) {}
|
||||
|
||||
template<class Type>
|
||||
void visit(Type val)
|
||||
{
|
||||
out << val << ",";
|
||||
}
|
||||
|
||||
std::ostream &out;
|
||||
};
|
||||
|
||||
|
||||
struct MyVoidNoParamIndexedVisitor : cv::util::static_indexed_visitor<void, MyVoidNoParamIndexedVisitor>
|
||||
{
|
||||
MyVoidNoParamIndexedVisitor(std::ostream &output) : out(output) {}
|
||||
|
||||
template<class Type>
|
||||
void visit(std::size_t Index, Type val)
|
||||
{
|
||||
out << Index << ":" << val <<",";
|
||||
}
|
||||
|
||||
std::ostream &out;
|
||||
};
|
||||
}
|
||||
|
||||
TEST(Variant, DynamicVisitor)
|
||||
{
|
||||
using V = cv::util::variant<int, double, char, float, test_validation::MyType, test_validation::MyClass>;
|
||||
V var{42};
|
||||
{
|
||||
std::stringstream ss;
|
||||
test_validation::MyBoolParamIndexedVisitor visitor(ss);
|
||||
|
||||
EXPECT_TRUE(cv::util::visit(visitor, var, int{42}));
|
||||
EXPECT_EQ(ss.str(), std::string("0:42,"));
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
test_validation::MyBoolNoParamNonIndexedVisitor visitor(ss);
|
||||
|
||||
cv::util::visit(visitor, var);
|
||||
EXPECT_EQ(ss.str(), std::string("0:42,"));
|
||||
|
||||
var = double{1.0};
|
||||
EXPECT_TRUE(cv::util::visit(visitor, var));
|
||||
EXPECT_EQ(ss.str(), std::string("0:42,1:1,"));
|
||||
|
||||
var = char{'a'};
|
||||
EXPECT_TRUE(cv::util::visit(visitor, var));
|
||||
EXPECT_EQ(ss.str(), std::string("0:42,1:1,2:a,"));
|
||||
|
||||
var = float{6.0};
|
||||
EXPECT_TRUE(cv::util::visit(visitor, var));
|
||||
EXPECT_EQ(ss.str(), std::string("0:42,1:1,2:a,3:6,"));
|
||||
|
||||
var = test_validation::MyType{};
|
||||
EXPECT_TRUE(cv::util::visit(visitor, var));
|
||||
EXPECT_EQ(ss.str(), std::string("0:42,1:1,2:a,3:6,4:MyType,"));
|
||||
|
||||
var = test_validation::MyClass{};
|
||||
EXPECT_TRUE(cv::util::visit(visitor, var));
|
||||
EXPECT_EQ(ss.str(), std::string("0:42,1:1,2:a,3:6,4:MyType,5:MyClass,"));
|
||||
}
|
||||
|
||||
TEST(Variant, StaticVisitor)
|
||||
{
|
||||
using V = cv::util::variant<int, double, char, float, test_validation::MyType, test_validation::MyClass>;
|
||||
V var{42};
|
||||
std::stringstream ss;
|
||||
test_validation::MyVoidNoParamNonIndexedVisitor visitor(ss);
|
||||
|
||||
cv::util::visit(visitor, var);
|
||||
EXPECT_EQ(ss.str(), std::string("42,"));
|
||||
|
||||
var = double{1.0};
|
||||
cv::util::visit(visitor, var);
|
||||
EXPECT_EQ(ss.str(), std::string("42,1,"));
|
||||
|
||||
var = char{'a'};
|
||||
cv::util::visit(visitor, var);
|
||||
EXPECT_EQ(ss.str(), std::string("42,1,a,"));
|
||||
|
||||
var = float{6.0};
|
||||
cv::util::visit(visitor, var);
|
||||
EXPECT_EQ(ss.str(), std::string("42,1,a,6,"));
|
||||
|
||||
var = test_validation::MyType{};
|
||||
cv::util::visit(visitor, var);
|
||||
EXPECT_EQ(ss.str(), std::string("42,1,a,6,MyType,"));
|
||||
|
||||
var = test_validation::MyClass{};
|
||||
cv::util::visit(visitor, var);
|
||||
EXPECT_EQ(ss.str(), std::string("42,1,a,6,MyType,MyClass,"));
|
||||
}
|
||||
|
||||
TEST(Variant, StaticIndexedVisitor)
|
||||
{
|
||||
using V = cv::util::variant<int, double, char, float, test_validation::MyType, test_validation::MyClass>;
|
||||
V var{42};
|
||||
|
||||
std::stringstream ss;
|
||||
cv::util::visit(test_validation::MyVoidNoParamIndexedVisitor {ss}, var);
|
||||
EXPECT_EQ(ss.str(), std::string("0:42,"));
|
||||
|
||||
var = double{1.0};
|
||||
cv::util::visit(test_validation::MyVoidNoParamIndexedVisitor (ss), var);
|
||||
EXPECT_EQ(ss.str(), std::string("0:42,1:1,"));
|
||||
|
||||
var = char{'a'};
|
||||
cv::util::visit(test_validation::MyVoidNoParamIndexedVisitor (ss), var);
|
||||
EXPECT_EQ(ss.str(), std::string("0:42,1:1,2:a,"));
|
||||
|
||||
var = float{6.0};
|
||||
cv::util::visit(test_validation::MyVoidNoParamIndexedVisitor (ss), var);
|
||||
EXPECT_EQ(ss.str(), std::string("0:42,1:1,2:a,3:6,"));
|
||||
|
||||
var = test_validation::MyType{};
|
||||
cv::util::visit(test_validation::MyVoidNoParamIndexedVisitor (ss), var);
|
||||
EXPECT_EQ(ss.str(), std::string("0:42,1:1,2:a,3:6,4:MyType,"));
|
||||
|
||||
var = test_validation::MyClass{};
|
||||
cv::util::visit(test_validation::MyVoidNoParamIndexedVisitor (ss), var);
|
||||
EXPECT_EQ(ss.str(), std::string("0:42,1:1,2:a,3:6,4:MyType,5:MyClass,"));
|
||||
}
|
||||
|
||||
|
||||
TEST(Variant, LambdaVisitor)
|
||||
{
|
||||
using V = cv::util::variant<int, double, char, float, test_validation::MyType, test_validation::MyClass>;
|
||||
V var{42};
|
||||
{
|
||||
cv::util::visit(cv::util::overload_lambdas(
|
||||
[](int value) {
|
||||
EXPECT_EQ(value, 42);
|
||||
},
|
||||
[](double) {
|
||||
ADD_FAILURE() << "can't be called for `double`";
|
||||
},
|
||||
[](char) {
|
||||
ADD_FAILURE() << "can't be called for `char`";
|
||||
},
|
||||
[](float) {
|
||||
ADD_FAILURE() << "can't be called for `float`";
|
||||
},
|
||||
[](test_validation::MyType) {
|
||||
ADD_FAILURE() << "can't be called for `MyType`";
|
||||
},
|
||||
[](test_validation::MyClass) {
|
||||
ADD_FAILURE() << "can't be called for `MyClass`";
|
||||
},
|
||||
[](std::string) {
|
||||
ADD_FAILURE() << "can't be called for `std::string`, invalid type";
|
||||
}
|
||||
), var);
|
||||
}
|
||||
|
||||
var = 'c';
|
||||
{
|
||||
cv::util::visit(cv::util::overload_lambdas(
|
||||
[](int) {
|
||||
ADD_FAILURE() << "can't be called for `int`";
|
||||
},
|
||||
[](double) {
|
||||
ADD_FAILURE() << "can't be called for `double`";
|
||||
},
|
||||
[](char value) {
|
||||
EXPECT_EQ(value, 'c');
|
||||
},
|
||||
[](float) {
|
||||
ADD_FAILURE() << "can't be called for `float`";
|
||||
},
|
||||
[](test_validation::MyType) {
|
||||
ADD_FAILURE() << "can't be called for `MyType`";
|
||||
},
|
||||
[](test_validation::MyClass) {
|
||||
ADD_FAILURE() << "can't be called for `MyClass`";
|
||||
},
|
||||
[](std::string) {
|
||||
ADD_FAILURE() << "can't be called for `std::string`, invalid type";
|
||||
}
|
||||
), var);
|
||||
}
|
||||
}
|
||||
} // namespace opencv_test
|
||||
|
Loading…
Reference in New Issue
Block a user