2

I am trying to create a concept for use with boost::any. This concept should say that a class has ha member function with signatur void templateFunction(T t). I have gotten this to compile and working fine, but only for one type at a time. Is what I am trying to do impossible?

#include <iostream>

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/member.hpp>
#include <boost/type_erasure/free.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/any.hpp>

using namespace std;
namespace mpl = boost::mpl;
using namespace boost::type_erasure;

class Foo
{
    public:

        template <class T>
        void templateFunction(T t)
        {
            cout << t << endl;
        }
};

template<class C, class T>
struct has_template_function
{
    static void apply(C& cont, const T& arg) { cont.templateFunction(arg); }
};

namespace boost
{
    namespace type_erasure
    {
        template<class C, class T, class Base>
        struct concept_interface<has_template_function<C, T>, Base, C> : Base
        {
            void templateFunction(typename as_param<Base, const T&>::type arg)
            { call(has_template_function<C, T>(), *this, arg); }
        };
    }
}

int main()
{
    any<has_template_function<_self, int>, _self&> c = Foo();
    c.templateFunction(5);

    //Compile error: cannot convert parameter 1 from 'const char [6]' to 'const int &'
    //c.templateFunction("Hello");

    return 0;
}
Håkon
  • 190
  • 3
  • 11

1 Answers1

2

This is kind of possible by overloading, and documented in the official Boost.TypeErasure documentation.

The caveat is, as said in the comments:

You can't type-erase templates and keep their polymorphic nature

Therefore, you will have to specify the overloads explicitly in the requirements for your boost::typeerasure::any type.

You need to modify your concept interface as described in the docs, and add a string overload to the requirements section.

Your example, modified to handle overloads:

#include <iostream>

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/member.hpp>
#include <boost/type_erasure/free.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/any.hpp>
#include <string>
#include <utility>

using namespace std;
namespace mpl = boost::mpl;
using namespace boost::type_erasure;

struct FooStruct
{
    template <class T>
    void templateFunction(T t)
    {
        cout << t << endl;
    }
};

template<class T, class U>
struct has_template_function
{
    static void apply(T& t, const U& u) { t.templateFunction(u); }
};

namespace boost {
    namespace type_erasure {

        template<class T, class U, class Base, class Enable>
        struct concept_interface< ::has_template_function<T, U>, Base, T, Enable> : Base
        {
            typedef void _fun_defined;
            void templateFunction(typename as_param<Base, const U&>::type arg)
            {
                call(::has_template_function<T, U>(), *this, arg);
            }
        };

        template<class T, class U, class Base>
        struct concept_interface< ::has_template_function<T, U>, Base, T, typename Base::_fun_defined> : Base
        {
            using Base::templateFunction;
            void templateFunction(typename as_param<Base, const U&>::type arg)
            {
                call(::has_template_function<T, U>(), *this, arg);
            }
        };

    }
}

ostream& operator<<(ostream& os, const std::pair<int, string>& pair) {
    os << "(" << pair.first << ", " << pair.second << ")";
    return os;
}

int main()
{
    any<
        mpl::vector
        <
        has_template_function<_self, int>,
        has_template_function<_self, std::string>,
        has_template_function<_self, std::pair<int,std::string>>
        >
    , _self&> c = FooStruct();

    c.templateFunction(5);

    c.templateFunction("Hello");

    c.templateFunction(std::make_pair(5, "Hello"));

    return 0;
}
meastp
  • 682
  • 1
  • 7
  • 15