Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost type_erasure any with const member function

I want to access a getter of type-erased types in a vector. The getter is marked const. Somehow, the const-ness does not propagate to the boost::any wrapper object. The minimal example

#include <iostream>
#include <vector>

#include <boost/mpl/vector.hpp>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/member.hpp>

using namespace boost;
using namespace boost::type_erasure;

BOOST_TYPE_ERASURE_MEMBER((has_test), test, 1)

using AnyTest = any<mpl::vector<copy_constructible<>,
                                has_test<int(double)>,
                                relaxed>>;

struct ATest {
  int test(double x) const {
    return 5;
  }
};

int main() {
  auto xs = std::vector<AnyTest>{};
  xs.push_back(ATest{});

  for (const auto& x : xs) {
    std::cout << x.test(42.0) << '\n';
  }
}

results in an error saying

clang++ -O3 -std=c++14    minimal.cc   -o minimal
minimal.cc:28:18: error: member function 'test' not viable: 'this' argument has type 'const
      boost::type_erasure::any<boost::mpl::vector<boost::type_erasure::copy_constructible<boost::type_erasure::_self>, has_test<int (double),
      boost::type_erasure::_self>, boost::type_erasure::relaxed, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na,
      mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, boost::type_erasure::_self>', but
      function is not marked const
    std::cout << x.test(42.0) << '\n';
                 ^
minimal.cc:11:39: note: 'test' declared here
BOOST_TYPE_ERASURE_MEMBER((has_test), test, 1)
                                      ^
/opt/local/include/boost/type_erasure/member.hpp:133:9: note: expanded from macro 'BOOST_TYPE_ERASURE_MEMBER'
        member,                                                                             \
        ^
/opt/local/include/boost/type_erasure/member.hpp:242:64: note: expanded from macro 'BOOST_TYPE_ERASURE_MEMBER_I'
    BOOST_TYPE_ERASURE_MEMBER_II(namespace_name, concept_name, member, N)
                                                               ^
/opt/local/include/boost/type_erasure/member.hpp:170:44: note: expanded from macro 'BOOST_TYPE_ERASURE_MEMBER_II'
        typename rebind_any<Base, R>::type member(                                              \
                                           ^
1 error generated.
make: *** [minimal] Error 1

However, once const auto& x in the for-loop is changed to just auto& x, it works. What's the reason for this and how can I require the wrapper object to respect constness?

like image 462
Kevin Dungs Avatar asked Sep 23 '15 15:09

Kevin Dungs


1 Answers

You need to specify the const-ness in the concept like this:

using AnyTest = any<mpl::vector<
                    copy_constructible<>, 
                    has_test<int(double), const _self>, relaxed> 
                  >;

Found on the documentation page "Basic Usage"


Live On Coliru

// http://stackoverflow.com/questions/32743594/boost-type-erasure-any-with-const-member-function
#include <iostream>
#include <vector>

#include <boost/mpl/vector.hpp>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/member.hpp>

using namespace boost;
using namespace boost::type_erasure;

BOOST_TYPE_ERASURE_MEMBER((has_test), test, 1)

using AnyTest = any<mpl::vector<
                    copy_constructible<>, 
                    has_test<int(double), const _self>, relaxed> 
                  >;

struct ATest {
    int test(double) const { return 5; }
};

int main() {
    auto xs = std::vector<AnyTest>{};
    xs.push_back(ATest{});

    for (auto const &x : xs) {
        std::cout << x.test(42.0) << '\n';
    }
}

Prints

5
like image 170
sehe Avatar answered Oct 29 '22 07:10

sehe