Boost.Type_erasure: member function return _self

218 Views Asked by At

I want to use Boost.Type_erasure on a member function that returns the type itself. With _self as the return type, it is OK. However, when the return type changes to pair<_self, some_type>, an error occurs. The following code reproduces the problem.

#include <utility>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/member.hpp>

BOOST_TYPE_ERASURE_MEMBER((HasTest1), Test1, 0)
BOOST_TYPE_ERASURE_MEMBER((HasTest2), Test2, 0)

using boost::type_erasure::_self;
using std::pair;
using Type1 = boost::type_erasure::any<
    boost::mpl::vector<
    boost::type_erasure::copy_constructible<>,
    HasTest1<_self(), _self const>
    >,
    _self
>;
using Type2 = boost::type_erasure::any<
    boost::mpl::vector<
    boost::type_erasure::copy_constructible<>,
    HasTest2<pair<_self, int>(), _self const>
    >,
    _self
>;

int main() {
    struct test {
        test Test1() const { throw; }
        pair<test, int> Test2() const { throw; }
    };

    Type1{ test{} };// OK
    Type2{ test{} };// Error
    // Type2{ test{} }.Test2().first.Test2();// Expected to work
}

How can I fix this problem without using return arguments?

Sample error message:

main.cpp:6:1: error: no viable conversion from 'pair<test, [...]>' to 'pair<boost::type_erasure::_self, [...]>'

BOOST_TYPE_ERASURE_MEMBER((HasTest2), Test2, 0)

^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1

There are 1 best solutions below

0
cqdjyy01234 On

The following is the response from Steven Watanabe.

The library can only handle placeholders at the top level. There is no way to handle the general case, X<_self> automatically. This is essentially the same as covariant return types for virtual functions, which have similar restrictions.

To get the effect that you want, you'll need to define the concept_interface manually.

Alternatively, I use boost::any to work around.

#include <utility>
#include <boost/any.hpp>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/member.hpp>

BOOST_TYPE_ERASURE_MEMBER((HasTest), Test, 0)

using Type = boost::type_erasure::any<
    boost::mpl::vector<
    boost::type_erasure::copy_constructible<>,
    HasTest<boost::any()>
    >
>;

int main() {
    struct TestType {
        auto Test() {
            return std::make_pair(0, Type{ *this });
        }
    };
    auto obj = Type{ TestType{} }.Test();
    boost::any_cast<std::pair<int, Type>&>(obj).second.Test();
}