1 | // return_type_traits.hpp -- Boost Lambda Library --------------------------- |
---|---|

2 | |

3 | // Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) |

4 | // |

5 | // Distributed under the Boost Software License, Version 1.0. (See |

6 | // accompanying file LICENSE_1_0.txt or copy at |

7 | // http://www.boost.org/LICENSE_1_0.txt) |

8 | // |

9 | // For more information, see www.boost.org |

10 | |

11 | |

12 | #ifndef BOOST_LAMBDA_RETURN_TYPE_TRAITS_HPP |

13 | #define BOOST_LAMBDA_RETURN_TYPE_TRAITS_HPP |

14 | |

15 | #include "boost/mpl/has_xxx.hpp" |

16 | |

17 | #include <cstddef> // needed for the ptrdiff_t |

18 | |

19 | namespace boost { |

20 | namespace lambda { |

21 | |

22 | // Much of the type deduction code for standard arithmetic types |

23 | // from Gary Powell |

24 | |

25 | // different arities: |

26 | template <class Act, class A1> struct return_type_1; // 1-ary actions |

27 | template <class Act, class A1, class A2> struct return_type_2; // 2-ary |

28 | template <class Act, class Args> struct return_type_N; // >3- ary |

29 | |

30 | template <class Act, class A1> struct return_type_1_prot; |

31 | template <class Act, class A1, class A2> struct return_type_2_prot; // 2-ary |

32 | template <class Act, class A1> struct return_type_N_prot; // >3-ary |

33 | |

34 | |

35 | namespace detail { |

36 | |

37 | template<class> class return_type_deduction_failure {}; |

38 | |

39 | // In some cases return type deduction should fail (an invalid lambda |

40 | // expression). Sometimes the lambda expression can be ok, the return type |

41 | // just is not deducible (user defined operators). Then return type deduction |

42 | // should never be entered at all, and the use of ret<> does this. |

43 | // However, for nullary lambda functors, return type deduction is always |

44 | // entered, and there seems to be no way around this. |

45 | |

46 | // (the return type is part of the prototype of the non-template |

47 | // operator()(). The prototype is instantiated, even though the body |

48 | // is not.) |

49 | |

50 | // So, in the case the return type deduction should fail, it should not |

51 | // fail directly, but rather result in a valid but wrong return type, |

52 | // causing a compile time error only if the function is really called. |

53 | |

54 | |

55 | |

56 | } // end detail |

57 | |

58 | |

59 | |

60 | // return_type_X_prot classes -------------------------------------------- |

61 | // These classes are the first layer that gets instantiated from the |

62 | // lambda_functor_base sig templates. It will check whether |

63 | // the action is protectable and one of arguments is "protected" or its |

64 | // evaluation will otherwise result in another lambda functor. |

65 | // If this is a case, the result type will be another lambda functor. |

66 | |

67 | // The arguments are always non-reference types, except for comma action |

68 | // where the right argument can be a reference too. This is because it |

69 | // matters (in the builtin case) whether the argument is an lvalue or |

70 | // rvalue: int i; i, 1 -> rvalue; 1, i -> lvalue |

71 | |

72 | template <class Act, class A> struct return_type_1_prot { |

73 | public: |

74 | typedef typename |

75 | detail::IF< |

76 | is_protectable<Act>::value && is_lambda_functor<A>::value, |

77 | lambda_functor< |

78 | lambda_functor_base< |

79 | Act, |

80 | tuple<typename detail::remove_reference_and_cv<A>::type> |

81 | > |

82 | >, |

83 | typename return_type_1<Act, A>::type |

84 | >::RET type; |

85 | }; |

86 | |

87 | // take care of the unavoidable instantiation for nullary case |

88 | template<class Act> struct return_type_1_prot<Act, null_type> { |

89 | typedef null_type type; |

90 | }; |

91 | |

92 | // Unary actions (result from unary operators) |

93 | // do not have a default return type. |

94 | template<class Act, class A> struct return_type_1 { |

95 | typedef typename |

96 | detail::return_type_deduction_failure<return_type_1> type; |

97 | }; |

98 | |

99 | |

100 | namespace detail { |

101 | |

102 | template <class T> |

103 | class protect_conversion { |

104 | typedef typename boost::remove_reference<T>::type non_ref_T; |

105 | public: |

106 | |

107 | // add const to rvalues, so that all rvalues are stored as const in |

108 | // the args tuple |

109 | typedef typename detail::IF_type< |

110 | boost::is_reference<T>::value && !boost::is_const<non_ref_T>::value, |

111 | detail::identity_mapping<T>, |

112 | const_copy_argument<non_ref_T> // handles funtion and array |

113 | >::type type; // types correctly |

114 | }; |

115 | |

116 | } // end detail |

117 | |

118 | template <class Act, class A, class B> struct return_type_2_prot { |

119 | |

120 | // experimental feature |

121 | // We may have a lambda functor as a result type of a subexpression |

122 | // (if protect) has been used. |

123 | // Thus, if one of the parameter types is a lambda functor, the result |

124 | // is a lambda functor as well. |

125 | // We need to make a conservative choise here. |

126 | // The resulting lambda functor stores all const reference arguments as |

127 | // const copies. References to non-const are stored as such. |

128 | // So if the source of the argument is a const open argument, a bound |

129 | // argument stored as a const reference, or a function returning a |

130 | // const reference, that information is lost. There is no way of |

131 | // telling apart 'real const references' from just 'LL internal |

132 | // const references' (or it would be really hard) |

133 | |

134 | // The return type is a subclass of lambda_functor, which has a converting |

135 | // copy constructor. It can copy any lambda functor, that has the same |

136 | // action type and code, and a copy compatible argument tuple. |

137 | |

138 | |

139 | typedef typename boost::remove_reference<A>::type non_ref_A; |

140 | typedef typename boost::remove_reference<B>::type non_ref_B; |

141 | |

142 | typedef typename |

143 | detail::IF< |

144 | is_protectable<Act>::value && |

145 | (is_lambda_functor<A>::value || is_lambda_functor<B>::value), |

146 | lambda_functor< |

147 | lambda_functor_base< |

148 | Act, |

149 | tuple<typename detail::protect_conversion<A>::type, |

150 | typename detail::protect_conversion<B>::type> |

151 | > |

152 | >, |

153 | typename return_type_2<Act, non_ref_A, non_ref_B>::type |

154 | >::RET type; |

155 | }; |

156 | |

157 | // take care of the unavoidable instantiation for nullary case |

158 | template<class Act> struct return_type_2_prot<Act, null_type, null_type> { |

159 | typedef null_type type; |

160 | }; |

161 | // take care of the unavoidable instantiation for nullary case |

162 | template<class Act, class Other> struct return_type_2_prot<Act, Other, null_type> { |

163 | typedef null_type type; |

164 | }; |

165 | // take care of the unavoidable instantiation for nullary case |

166 | template<class Act, class Other> struct return_type_2_prot<Act, null_type, Other> { |

167 | typedef null_type type; |

168 | }; |

169 | |

170 | // comma is a special case, as the user defined operator can return |

171 | // an lvalue (reference) too, hence it must be handled at this level. |

172 | template<class A, class B> |

173 | struct return_type_2_comma |

174 | { |

175 | typedef typename boost::remove_reference<A>::type non_ref_A; |

176 | typedef typename boost::remove_reference<B>::type non_ref_B; |

177 | |

178 | typedef typename |

179 | detail::IF< |

180 | is_protectable<other_action<comma_action> >::value && // it is protectable |

181 | (is_lambda_functor<A>::value || is_lambda_functor<B>::value), |

182 | lambda_functor< |

183 | lambda_functor_base< |

184 | other_action<comma_action>, |

185 | tuple<typename detail::protect_conversion<A>::type, |

186 | typename detail::protect_conversion<B>::type> |

187 | > |

188 | >, |

189 | typename |

190 | return_type_2<other_action<comma_action>, non_ref_A, non_ref_B>::type |

191 | >::RET type1; |

192 | |

193 | // if no user defined return_type_2 (or plain_return_type_2) specialization |

194 | // matches, then return the righthand argument |

195 | typedef typename |

196 | detail::IF< |

197 | boost::is_same<type1, detail::unspecified>::value, |

198 | B, |

199 | type1 |

200 | >::RET type; |

201 | |

202 | }; |

203 | |

204 | |

205 | // currently there are no protectable actions with > 2 args |

206 | |

207 | template<class Act, class Args> struct return_type_N_prot { |

208 | typedef typename return_type_N<Act, Args>::type type; |

209 | }; |

210 | |

211 | // take care of the unavoidable instantiation for nullary case |

212 | template<class Act> struct return_type_N_prot<Act, null_type> { |

213 | typedef null_type type; |

214 | }; |

215 | |

216 | // handle different kind of actions ------------------------ |

217 | |

218 | // use the return type given in the bind invocation as bind<Ret>(...) |

219 | template<int I, class Args, class Ret> |

220 | struct return_type_N<function_action<I, Ret>, Args> { |

221 | typedef Ret type; |

222 | }; |

223 | |

224 | // ::result_type support |

225 | |

226 | namespace detail |

227 | { |

228 | |

229 | BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type) |

230 | |

231 | template<class F> struct get_result_type |

232 | { |

233 | typedef typename F::result_type type; |

234 | }; |

235 | |

236 | template<class F, class A> struct get_sig |

237 | { |

238 | typedef typename function_adaptor<F>::template sig<A>::type type; |

239 | }; |

240 | |

241 | } // namespace detail |

242 | |

243 | // Ret is detail::unspecified, so try to deduce return type |

244 | template<int I, class Args> |

245 | struct return_type_N<function_action<I, detail::unspecified>, Args > { |

246 | |

247 | // in the case of function action, the first element in Args is |

248 | // some type of function |

249 | typedef typename Args::head_type Func; |

250 | typedef typename detail::remove_reference_and_cv<Func>::type plain_Func; |

251 | |

252 | public: |

253 | // pass the function to function_adaptor, and get the return type from |

254 | // that |

255 | typedef typename detail::IF< |

256 | detail::has_result_type<plain_Func>::value, |

257 | detail::get_result_type<plain_Func>, |

258 | detail::get_sig<plain_Func, Args> |

259 | >::RET::type type; |

260 | }; |

261 | |

262 | |

263 | } // namespace lambda |

264 | } // namespace boost |

265 | |

266 | #endif |

267 | |

268 | |

269 | |

270 |