Skip to content

Commit

Permalink
don't let sfinae_errors get passed as arguments to functions. just re…
Browse files Browse the repository at this point in the history
…turn them.
  • Loading branch information
Eric Niebler committed Aug 14, 2012
1 parent 2751782 commit 4f1efce
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 38 deletions.
10 changes: 3 additions & 7 deletions TODO.txt
Expand Up @@ -3,18 +3,12 @@ Implement proper lexical scoping for let expressions.

Think about basic actions.
- Is the interface correct?
- Maybe the environment should be the second parameter ans state should be third.
- Maybe the environment should be the second parameter and state should be third.
- Should the local variable scope be part of the environment, or should it be a
fourth parameter?
- Should *all* environment variables be part of a scope? Should we allow
non-environments in the environments parameter as Proto-current does?

Think about poor SFINAE error reporting cause by too-extensive use of BOOST_PROTO_AUTO_RETURN.

Related to the SFINAE thing: Can something be done about deep template instantion backtraces?
Would it be possible to use something like Haskell's Either monad to transport the offending
code closer to Proto's API boundary?

Thoughts about construct(foo<some_action<int>>())
- It doesn't invoke some_action. Should it? With what semantics? Is it right to be looking
for a nested ::type after substitution, or should it be checking for action-ness instead
Expand All @@ -24,6 +18,8 @@ How about a static_cast_ function object?

Should terminal-ness really be encoded in the tag?

I don't really like the use of enable_if<!is_tag...> in action specialization for callables.

Functional namespace should be carved up: proto::functional::fusion? proto::functional::std?

Should or_/when be renamed match/case_?
Expand Down
4 changes: 3 additions & 1 deletion boost/proto/action/apply.hpp
Expand Up @@ -11,8 +11,10 @@
#define BOOST_PROTO_ACTION_APPLY_HPP_INCLUDED

#include <boost/proto/proto_fwd.hpp>
#include <boost/proto/utility.hpp>
#include <boost/proto/action/action.hpp>
#include <boost/proto/action/call.hpp>
#include <boost/proto/utility.hpp>

namespace boost
{
Expand All @@ -27,7 +29,7 @@ namespace boost
template<typename ...Args>
auto operator()(Args &&... args) const
BOOST_PROTO_AUTO_RETURN(
BOOST_PROTO_TRY_CALL(detail::call_1_<Actions...>())(
detail::call_1_<Actions...>()(
action<Fun>()(static_cast<Args &&>(args)...)
, static_cast<Args &&>(args)...
)
Expand Down
6 changes: 3 additions & 3 deletions boost/proto/action/call.hpp
Expand Up @@ -72,10 +72,10 @@ namespace boost
>
auto operator()(Action &&act, Args &&... args) const
BOOST_PROTO_AUTO_RETURN(
BOOST_PROTO_TRY_CALL(call_2_<
call_2_<
(sizeof...(Args) <= sizeof...(Actions))
, decltype(action<Actions>()(static_cast<Args &&>(args)...))...
>())(
>()(
static_cast<Action &&>(act)
, action<Actions>()(static_cast<Args &&>(args)...)...
, static_cast<Args &&>(args)...
Expand Down Expand Up @@ -105,7 +105,7 @@ namespace boost
template<typename ...Args, typename Fun = Ret>
auto operator()(Args &&... t) const
BOOST_PROTO_AUTO_RETURN(
BOOST_PROTO_TRY_CALL(call_1_<Actions...>())(Fun(), static_cast<Args &&>(t)...)
call_1_<Actions...>()(Fun(), static_cast<Args &&>(t)...)
)
};
}
Expand Down
2 changes: 1 addition & 1 deletion boost/proto/action/construct.hpp
Expand Up @@ -54,7 +54,7 @@ namespace boost
template<bool IsAction, typename R, typename ...Args>
struct make_3_
{
typedef decltype(utility::by_val()(BOOST_PROTO_TRY_CALL(R())(std::declval<Args>()...))) type;
typedef decltype(utility::by_val()(action<R>()(std::declval<Args>()...))) type;
typedef std::true_type applied;
};

Expand Down
4 changes: 2 additions & 2 deletions boost/proto/action/env.hpp
Expand Up @@ -75,10 +75,10 @@ namespace boost
template<typename T, typename V>
friend env<T, V, env> operator,(env tail, env<T, V> head)
{
return env<T, V, env>{
return env<T, V, env>(
static_cast<env<T, V> &&>(head).value_
, static_cast<env &&>(tail)
};
);
}
};
}
Expand Down
2 changes: 1 addition & 1 deletion boost/proto/operators.hpp
Expand Up @@ -140,7 +140,7 @@ namespace boost
template<typename Domain, typename ...U>
inline constexpr auto expr_maker_if(Domain, U const &...u)
BOOST_PROTO_AUTO_RETURN(
detail::make_expr_if_<decltype(detail::get_common_domain(Domain(), u...))>{}
detail::make_expr_if_<decltype(detail::get_common_domain(Domain(), u...))>()
)

////////////////////////////////////////////////////////////////////////////////////////
Expand Down
11 changes: 5 additions & 6 deletions boost/proto/proto_fwd.hpp
Expand Up @@ -92,12 +92,6 @@ namespace boost
typedef T && type;
};

template<typename T>
struct rvalue_type<T &>
{
typedef T && type;
};

template<>
struct rvalue_type<void>
{
Expand Down Expand Up @@ -130,6 +124,11 @@ namespace boost
// sized_type
template<int N>
struct sized_type;

////////////////////////////////////////////////////////////////////////////////////////
// sfinae_error
template<typename Sig>
struct sfinae_error;
}

///////////////////////////////////////////////////////////////////////////////
Expand Down
6 changes: 3 additions & 3 deletions boost/proto/tags.hpp
Expand Up @@ -191,12 +191,12 @@ namespace boost
BOOST_PROTO_REGULAR_TRIVIAL_CLASS(env_var_tag);

// So that tag objects of type (derived from) env_var_tag can be used
// to create basic_action environments like (data=x, local=y),
// where "data" and "local" are tags.
// to create basic_action environments like (data=x, myvar=y),
// where "data" and "myvar" are tags.
template<typename V, BOOST_PROTO_ENABLE_IF(!(utility::is_base_of<env_var_tag, V>::value))>
env<Tag, V> operator=(V && v) const
{
return env<Tag, V>{static_cast<V &&>(v)};
return env<Tag, V>(static_cast<V &&>(v));
}
};

Expand Down
70 changes: 58 additions & 12 deletions boost/proto/utility.hpp
Expand Up @@ -21,6 +21,22 @@ namespace boost
// none
struct none
{};

////////////////////////////////////////////////////////////////////////////////////////
// find_first_sfinae_error
template<typename ...Args>
struct find_first_sfinae_error;

template<typename Head, typename ...Tail>
struct find_first_sfinae_error<Head, Tail...>
: find_first_sfinae_error<Tail...>
{};

template<typename Sig, typename ...Tail>
struct find_first_sfinae_error<utility::sfinae_error<Sig>, Tail...>
{
typedef utility::sfinae_error<Sig> type;
};
}

namespace utility
Expand Down Expand Up @@ -607,44 +623,74 @@ namespace boost

////////////////////////////////////////////////////////////////////////////////////////
// sfinae_error
template<typename Sig>
struct sfinae_error;
struct sfinae_error_base
{
template<typename ...Args>
friend typename detail::find_first_sfinae_error<Args...>::type
boost_proto_try_find_errors(int, Args &&...args) noexcept
{
return typename detail::find_first_sfinae_error<Args...>::type();
}
};

template<typename Fun, typename ...Args>
struct sfinae_error<Fun(Args...)>
: sfinae_error_base
{
virtual void what() const noexcept
{
typedef decltype(std::declval<Fun>()(std::declval<Args>()...)) type;
typedef decltype(std::declval<Fun>()(std::declval<Args>()...)) error_message;
}
};

template<typename ...Args>
inline int boost_proto_try_find_errors(long, Args &&...) noexcept
{
return 0;
}

////////////////////////////////////////////////////////////////////////////////////////
// Many thanks to Paul Fultz for the ideas behind the try_call function wrapper
// Many thanks to Paul Fultz for some of the ideas behind try_call
template<typename Fun>
struct try_call_wrapper
class try_call_wrapper
{
Fun fun_;

template<typename ...Args>
auto call_or_fail_(int, Args &&... args) const
BOOST_PROTO_AUTO_RETURN(
fun_(static_cast<Args &&>(args)...)
)

template<typename Sig, typename ...Args>
sfinae_error<Sig> call_or_fail_(sfinae_error<Sig>, Args &&... args) const noexcept
{
return sfinae_error<Sig>();
}

public:
BOOST_PROTO_REGULAR_TRIVIAL_CLASS(try_call_wrapper);

explicit try_call_wrapper(Fun &&fun)
explicit constexpr try_call_wrapper(Fun &&fun)
noexcept(noexcept(Fun(static_cast<Fun &&>(fun))))
: fun_(static_cast<Fun &&>(fun))
{}

template<typename ...Args>
auto operator()(Args &&...args) const
BOOST_PROTO_AUTO_RETURN(
fun_(static_cast<Args &&>(args)...)
this->call_or_fail_(
// Must be an unqualified call to possibly find the sfinae_error friend function
boost_proto_try_find_errors(1, static_cast<Args &&>(args)...)
, static_cast<Args &&>(args)...
)
)

template<typename ...Args>
sfinae_error<Fun(Args...)> operator()(Args &&...args) const volatile noexcept
sfinae_error<Fun(Args...)> operator()(Args &&...) const volatile noexcept
{
// Uncomment the next 2 lines to get the full template instantiation backtrace
//auto & fun = const_cast<try_call_wrapper<Fun> const &>(*this).fun_;
//fun(static_cast<Args &&>(args)...);
utility::ignore(args...);
// Uncomment this line to get the full template instantiation backtrace
//const_cast<try_call_wrapper const *>(this)->fun_(static_cast<Args &&>(args)...);
return sfinae_error<Fun(Args...)>();
}
};
Expand Down
19 changes: 17 additions & 2 deletions libs/proto/scratch/main.cpp
Expand Up @@ -16,13 +16,28 @@ namespace proto = boost::proto;
using proto::_;

struct foo
{};
{
int m;
};

struct S
{
int m;
};

int main()
{
proto::literal<S> s;
proto::value(s).m = 42;

proto::_eval<> eval;
auto x = eval( proto::literal<int>(42) + 36 );
auto y = eval( proto::literal<int>(42) + foo() );
auto y = eval( 1+ 2 * (proto::literal<int>(42) + foo()) );

//int i = eval(s ->* &S::m);
//std::cout << "i == " << i << std::endl;

//eval(s ->* &foo::m);

void done();
done();
Expand Down

0 comments on commit 4f1efce

Please sign in to comment.