Boost :: option and overload function

The following code does not compile:

#include <boost/variant.hpp> class A {}; class B {}; class C {}; class D {}; using v1 = boost::variant<A, B>; using v2 = boost::variant<C, D>; int f(v1 const&) { return 0; } int f(v2 const&) { return 1; } int main() { return f(A{}); } 

both gcc and clang complain about:

 test1.cpp: In function 'int main()': test1.cpp:18:17: error: call of overloaded 'f(A)' is ambiguous return f(A{}); ^ test1.cpp:18:17: note: candidates are: test1.cpp:11:5: note: int f(const v1&) int f(v1 const&) { ^ test1.cpp:14:5: note: int f(const v2&) int f(v2 const&) { 

Given that it is not possible to build the v2 object from instance A , why does the compiler give the same priority to both functions during overload resolution?

+6
source share
2 answers

The problem is the constructor

 template<typename T> variant(const T&) 

of boost::variant . The code below reproduces the problem without any magic:

 struct C {}; struct A { A(const C&) {} template<typename T> A(const T&) {} }; struct B { template<typename T> B(const T&) {} }; int f(const A&) { return 0; } int f(const B&) { return 1; } int main() { return f(C{}); } 

I think the variant constructor should be included only if the argument is actually converted to arguments, you might want to raise this as an error.

+5
source

A pragmatic approach not involving an explicit conversion with the correct SFINAE (I don’t think it can be done elegantly outside the Boost Variant library) could be as follows:

Watch Live On Coliru

 #include <boost/variant.hpp> class A {}; class B {}; class C {}; class D {}; using v1 = boost::variant<A, B>; using v2 = boost::variant<C, D>; namespace detail { struct F : boost::static_visitor<int> { template <typename... T> int operator()(boost::variant<T...> const& v) const { return boost::apply_visitor(*this, v); } int operator()(A) const { return 0; } int operator()(B) const { return 0; } int operator()(C) const { return 1; } int operator()(D) const { return 1; } } _f; } template <typename T> int f(T const& t) { return detail::F()(t); } int main() { std::cout << f(A{}) << "\n"; std::cout << f(B{}) << "\n"; std::cout << f(C{}) << "\n"; std::cout << f(D{}) << "\n"; std::cout << f(v1{}) << "\n"; std::cout << f(v2{}) << "\n"; } 

Print

 0 0 1 1 0 1 

It is assumed that f(T) always returns the same value for the same T , even if it is a member of more than one variant

+3
source

Source: https://habr.com/ru/post/972347/


All Articles