|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r51821 - in trunk: boost/proto boost/proto/transform libs/proto/doc/reference/transform libs/proto/test
From: eric_at_[hidden]
Date: 2009-03-17 14:21:41
Author: eric_niebler
Date: 2009-03-17 14:21:40 EDT (Tue, 17 Mar 2009)
New Revision: 51821
URL: http://svn.boost.org/trac/boost/changeset/51821
Log:
add proto::noinvoke to block metafunction invocation in ObjectTransforms
Added:
trunk/libs/proto/test/noinvoke.cpp (contents, props changed)
Text files modified:
trunk/boost/proto/proto_fwd.hpp | 3 +
trunk/boost/proto/transform/make.hpp | 22 ++++++++-
trunk/libs/proto/doc/reference/transform/make.xml | 83 +++++++++++++++++++++++++++++++++++++++
trunk/libs/proto/test/Jamfile.v2 | 1
4 files changed, 103 insertions(+), 6 deletions(-)
Modified: trunk/boost/proto/proto_fwd.hpp
==============================================================================
--- trunk/boost/proto/proto_fwd.hpp (original)
+++ trunk/boost/proto/proto_fwd.hpp 2009-03-17 14:21:40 EDT (Tue, 17 Mar 2009)
@@ -712,6 +712,9 @@
template<typename PrimitiveTransform>
struct protect;
+ template<typename T>
+ struct noinvoke;
+
template<typename Fun>
struct lazy;
Modified: trunk/boost/proto/transform/make.hpp
==============================================================================
--- trunk/boost/proto/transform/make.hpp (original)
+++ trunk/boost/proto/transform/make.hpp 2009-03-17 14:21:40 EDT (Tue, 17 Mar 2009)
@@ -292,6 +292,9 @@
typedef void not_applied_;
};
+ #define TMP0(Z, M, DATA) make_if_<BOOST_PP_CAT(A, M), Expr, State, Data>
+ #define TMP1(Z, M, DATA) typename TMP0(Z, M, DATA) ::type
+
template<
template<BOOST_PP_ENUM_PARAMS(N, typename BOOST_PP_INTERCEPT)> class R
BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)
@@ -301,14 +304,25 @@
BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(N)
>
: nested_type_if<
- #define TMP0(Z, M, DATA) make_if_<BOOST_PP_CAT(A, M), Expr, State, Data>
- #define TMP1(Z, M, DATA) typename TMP0(Z, M, DATA) ::type
R<BOOST_PP_ENUM(N, TMP1, ~)>
, typelist<BOOST_PP_ENUM(N, TMP0, ~) >
- #undef TMP0
- #undef TMP1
>
{};
+
+ template<
+ template<BOOST_PP_ENUM_PARAMS(N, typename BOOST_PP_INTERCEPT)> class R
+ BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)
+ , typename Expr, typename State, typename Data
+ >
+ struct make_<noinvoke<R<BOOST_PP_ENUM_PARAMS(N, A)> >, Expr, State, Data
+ BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(N)
+ >
+ {
+ typedef R<BOOST_PP_ENUM(N, TMP1, ~)> type;
+ };
+
+ #undef TMP0
+ #undef TMP1
#endif
template<
Modified: trunk/libs/proto/doc/reference/transform/make.xml
==============================================================================
--- trunk/libs/proto/doc/reference/transform/make.xml (original)
+++ trunk/libs/proto/doc/reference/transform/make.xml 2009-03-17 14:21:40 EDT (Tue, 17 Mar 2009)
@@ -13,6 +13,56 @@
</para>
<namespace name="boost">
<namespace name="proto">
+ <struct name="noinvoke">
+ <template>
+ <template-type-parameter name="T"/>
+ </template>
+ <purpose>A type annotation in an <conceptname>ObjectTransform</conceptname> which instructs
+ Proto not to look for a nested <computeroutput>::type</computeroutput> within
+ <computeroutput>T</computeroutput> after type substitution.</purpose>
+ <description>
+ <para>
+ <conceptname>ObjectTransform</conceptname>s are evaluated by
+ <computeroutput><classname alt="proto::make">proto::make<></classname></computeroutput>,
+ which finds all nested transforms and replaces them with the result of their applications.
+ If any substitutions are performed, the result is first assumed to be a metafunction to be applied;
+ that is, Proto checks to see if the result has a nested <computeroutput>::type</computeroutput>
+ typedef. If it does, that becomes the result. The purpose of <computeroutput>proto::noinvoke<></computeroutput>
+ is to prevent Proto from looking for a nested <computeroutput>::type</computeroutput> typedef
+ in these situations.
+ </para>
+ <para>
+ Example:
+ <programlisting>struct Test
+ : <classname>proto::when</classname><
+ <classname>_</classname>
+ , proto::noinvoke<
+ // This remove_pointer invocation is bloked by noinvoke
+ boost::remove_pointer<
+ // This add_pointer invocation is *not* blocked by noinvoke
+ boost::add_pointer<<classname>_</classname>>
+ >
+ >()
+ >
+{};
+
+void test_noinvoke()
+{
+ typedef <classname>proto::terminal</classname><int>::type Int;
+
+ BOOST_MPL_ASSERT((
+ boost::is_same<
+ boost::result_of<Test(Int)>::type
+ , boost::remove_pointer<Int *>
+ >
+ ));
+
+ Int i = {42};
+ boost::remove_pointer<Int *> t = Test()(i);
+}</programlisting>
+ </para>
+ </description>
+ </struct>
<struct name="protect">
<template>
<template-type-parameter name="PrimitiveTransform"/>
@@ -121,7 +171,6 @@
<computeroutput><classname>proto::make</classname><T>::impl<Expr, State, Data>::result_type</computeroutput> is
computed as follows:
</para>
-
<para>
If <computeroutput>T</computeroutput> is an <conceptname>ObjectTransform</conceptname> of the form
<computeroutput>Object(A<subscript>0</subscript>,...A<subscript>n</subscript>)</computeroutput>,
@@ -143,7 +192,37 @@
</para>
</listitem>
<listitem>
- Otherwise, if <computeroutput>O</computeroutput> is a template like
+ If <computeroutput>O</computeroutput> is a template like
+ <computeroutput><classname>proto::noinvoke</classname><S<X<subscript>0</subscript>,...X<subscript>n</subscript>> ></computeroutput>,
+ then the result type is calculated as follows:
+ <itemizedlist>
+ <listitem>
+ <para>
+ For each <computeroutput>i</computeroutput> in
+ <computeroutput>[0,n]</computeroutput>, let <computeroutput>
+ X<subscript>i</subscript>'
+ </computeroutput> be
+ <computeroutput>
+ boost::result_of<<classname>proto::make</classname><X<subscript>i</subscript>>(Expr, State, Data)>::type
+ </computeroutput>
+ (which evaluates this procedure recursively). Note that a substitution took place. (In this case,
+ Proto merely assumes that a substitution took place for the sake of compile-time efficiency. There
+ would be no reason to use <computeroutput><classname>proto::noinvoke<></classname></computeroutput>
+ otherwise.)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The result type is
+ <computeroutput>
+ S<X<subscript>0</subscript>',...X<subscript>n</subscript>'>
+ </computeroutput>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ If <computeroutput>O</computeroutput> is a template like
<computeroutput>S<X<subscript>0</subscript>,...X<subscript>n</subscript>></computeroutput>,
then the result type is calculated as follows:
<itemizedlist>
Modified: trunk/libs/proto/test/Jamfile.v2
==============================================================================
--- trunk/libs/proto/test/Jamfile.v2 (original)
+++ trunk/libs/proto/test/Jamfile.v2 2009-03-17 14:21:40 EDT (Tue, 17 Mar 2009)
@@ -29,6 +29,7 @@
[ run proto_fusion_s.cpp ]
[ run toy_spirit.cpp ]
[ run toy_spirit2.cpp ]
+ [ run noinvoke.cpp ]
[ compile bug2407.cpp ]
;
Added: trunk/libs/proto/test/noinvoke.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/proto/test/noinvoke.cpp 2009-03-17 14:21:40 EDT (Tue, 17 Mar 2009)
@@ -0,0 +1,81 @@
+///////////////////////////////////////////////////////////////////////////////
+// noinvoke.hpp
+//
+// Copyright 2008 Eric Niebler. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/proto/core.hpp>
+#include <boost/proto/transform/make.hpp>
+#include <boost/type_traits/add_pointer.hpp>
+#include <boost/type_traits/remove_pointer.hpp>
+#include <boost/test/unit_test.hpp>
+namespace proto=boost::proto;
+using proto::_;
+
+struct Test
+ : proto::when<
+ _
+ , proto::noinvoke<
+ // This remove_pointer invocation is bloked by noinvoke
+ boost::remove_pointer<
+ // This add_pointer invocation is *not* blocked by noinvoke
+ boost::add_pointer<_>
+ >
+ >()
+ >
+{};
+
+struct Test2
+ : proto::when<
+ _
+ // This add_pointer gets invoked because a substitution takes place
+ // within it.
+ , boost::add_pointer<
+ proto::noinvoke<
+ // This remove_pointer invocation is bloked by noinvoke
+ boost::remove_pointer<
+ // This add_pointer invocation is *not* blocked by noinvoke
+ boost::add_pointer<_>
+ >
+ >
+ >()
+ >
+{};
+
+void test_noinvoke()
+{
+ typedef proto::terminal<int>::type Int;
+ Int i = {42};
+
+ BOOST_MPL_ASSERT((
+ boost::is_same<
+ boost::result_of<Test(Int)>::type
+ , boost::remove_pointer<Int *>
+ >
+ ));
+
+ boost::remove_pointer<Int *> t = Test()(i);
+
+ BOOST_MPL_ASSERT((
+ boost::is_same<
+ boost::result_of<Test2(Int)>::type
+ , boost::remove_pointer<Int *> *
+ >
+ ));
+
+ boost::remove_pointer<Int *> * t2 = Test2()(i);
+}
+
+using namespace boost::unit_test;
+///////////////////////////////////////////////////////////////////////////////
+// init_unit_test_suite
+//
+test_suite* init_unit_test_suite( int argc, char* argv[] )
+{
+ test_suite *test = BOOST_TEST_SUITE("test proto::noinvoke");
+
+ test->add(BOOST_TEST_CASE(&test_noinvoke));
+
+ return test;
+}
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk