5

Is there, or how would you write, a metafunction class that tests whether a class is compatible with boost::range? I want to use the boost::enable idiom, something like

template <typename T>
Constructor::Constructor(const T& t, __attribute__((unused)) typename boost::enable_if<is_range_compatible<T> >::type* aux=NULL)

for an appropriate is_range_compatible metafunction. I know about is_container from pretty_print, which captures a lot of cases, but not everything that works with boost::range.

Edit This is using C++03, so I don't have access to C++11 features. I'm using an old, gcc 4.1, and boost 1.51.

Community
  • 1
  • 1
pythonic metaphor
  • 9,476
  • 16
  • 59
  • 103
  • Boost already has a solution: [Concepts checking.](http://www.boost.org/doc/libs/1_54_0/libs/range/doc/html/range/concepts/concept_checking.html) – jrok Aug 20 '13 at 14:36
  • 1
    Seems to be similar to [this question](http://stackoverflow.com/questions/14439479/detecting-whether-something-is-boost-range-with-sfinae). – llonesmiz Aug 20 '13 at 14:45
  • Do you have access to C++11, or not ? Because meta-programming is slightly easier with `decltype` and late-specified returns. – Matthieu M. Aug 20 '13 at 15:02
  • @cv_and_he it does look like `boost::has_range_const_iterator` may do what I want. – pythonic metaphor Aug 20 '13 at 15:10

2 Answers2

0

Do you mean enable_if?

If you can persuade the Boost concept checks to work usefully with it (instead of the macro + compile error it uses now), checks like ForwardConceptRange are already provided.

Otherwise, is it a problem to use the existing BOOST_CONCEPT_ASSERT macro instead?

Useless
  • 55,472
  • 5
  • 73
  • 117
  • I wanted to use SFINAE (a name I only learned from seeing the suggested duplicate), which I don't get with the asserts. One of the nice things about `boost::range` is that it can take things like pairs of iterators, which I don't will work with boost concept checks, though I don't understand them very well. – pythonic metaphor Aug 20 '13 at 15:33
  • There's specifically a set of boost concept checks for ranges, I'll add a link. Though, as I say, they don't seem to work out of the box with SFINAE. – Useless Aug 20 '13 at 16:12
  • ... done, although I just noticed jrok already offered the same link. If `has_range_const_iterator` works for you, it'll be easier though. – Useless Aug 20 '13 at 16:18
0

If you upgrade to Boost 1.54, there is a nice library called TTI. It allows you to compose type traits introspection meta functions at will, so that you can easily spin off you own meta predicates which can be used to enable or disable function templates. Though it is a nice meta programming exercise, I don't recommend to do that in production code. I found it hard to catch the "false negatives" which arise from implementation details of STL containers. For example, the associative containers coming with MSVC11 inherit their begin and end member functions from a base class which yields false negative with meta predicates generated via BOOST_TTI_HAS_MEMBER_FUNCTION. Despite of his nickname, Useless gave you a good advice: Use concepts coming with Boost.Range to reject or accept the type inside the body of the function template such as the constructor in your example... Of course, this will not solve the convertibility problem for your Constructor...

EDIT: example, taken from vex:

#include <boost/tti/has_member_function.hpp>
#include <vector>
#include <map>

namespace tti_test {
    BOOST_TTI_HAS_MEMBER_FUNCTION(begin);

    // .. begin test class for mstest

    // this succeeds in both variants
    TEST_METHOD(has_const_member_function_begin_is_true_for_vector)
    {
        Assert::IsTrue(has_member_function_begin<
            std::vector<int>::const_iterator (std::vector<int>::*)() const
        >::value);

        Assert::IsTrue(has_member_function_begin<
            const std::vector<int>, std::vector<int>::const_iterator
        >::value);
    }

    // this fails in both variants...
    TEST_METHOD(has_const_member_function_begin_is_true_for_map)
    {
        Assert::IsTrue(has_member_function_begin<
            std::map<int, int>::const_iterator (std::map<int, int>::*)() const
        >::value);

        Assert::IsTrue(has_member_function_begin<
            const std::map<int, int>, std::map<int, int>::const_iterator
        >::value);
    }

    // end test class for mstest
}
Paul Michalik
  • 4,147
  • 14
  • 18