utils/call_with.hh

00001 // This file is a part of Catsfoot.
00002 // Copyright (C) 2011  Uni Research
00003 //
00004 // This program is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU Lesser Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser Public License
00015 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 #ifndef CALL_WITH_HH
00018 # define CALL_WITH_HH
00019 
00020 # include <tuple>
00021 # include "../concept/concepts.hh"
00022 
00023 namespace catsfoot {
00024 
00025   namespace details {
00026     template <typename T>
00027     struct add_const_ref {
00028       typedef const T& type;
00029     };
00030 
00031     template <typename T>
00032     struct add_ref {
00033       typedef T& type;
00034     };
00035 
00036     template <typename Op, typename Tuple>
00037     struct call_with_ret {
00038     };
00039 
00040     template <typename Op, typename... Args>
00041     struct call_with_ret<Op, std::tuple<Args...>&> {
00042       typedef
00043       decltype(std::declval<Op>()(std::declval<typename add_ref<Args>::type>()...))
00044       type;
00045       static const size_t size = sizeof...(Args);
00046     };
00047 
00048     template <typename Op, typename... Args>
00049     struct call_with_ret<Op, std::tuple<Args...> > {
00050       typedef
00051       decltype(std::declval<Op>()(std::declval<typename add_ref<Args>::type>()...))
00052       type;
00053       static const size_t size = sizeof...(Args);
00054     };
00055 
00056     template <typename Op, typename... Args>
00057     struct call_with_ret<Op, const std::tuple<Args...>&> {
00058       typedef
00059       decltype(std::declval<Op>()(std::declval<typename add_const_ref<Args>::type>()...))
00060       type;
00061       static const size_t size = sizeof...(Args);
00062     };
00063 
00064     template <typename Op, typename Tuple,
00065               typename... Given,
00066               typename = typename std::enable_if<(sizeof...(Given) == call_with_ret<Op, Tuple>::size)>::type>
00067     typename call_with_ret<Op, Tuple>::type
00068     call_with_it(Op&& op, Tuple&&, Given&&... args) {
00069       return std::forward<Op>(op)(std::forward<Given>(args)...);
00070     }
00071 
00072     template <typename Op, typename Tuple,
00073               typename... OtherArgs,
00074               typename = typename std::enable_if<(sizeof...(OtherArgs) != call_with_ret<Op, Tuple>::size)>::type,
00075               typename = void>
00076     typename call_with_ret<Op, Tuple>::type
00077     call_with_it(Op&& op, Tuple&& args,
00078                  OtherArgs&&... otherargs) {
00079       return call_with_it(std::forward<Op>(op), std::forward<Tuple>(args),
00080                           std::forward<OtherArgs>(otherargs)...,
00081                           std::get<sizeof...(OtherArgs)>(args));
00082     }
00083   }
00084 
00090   template <typename Op, typename Tuple>
00091   typename details::call_with_ret<Op, Tuple>::type
00092   call_with(Op&& op, Tuple&& args) {
00093     return details::call_with_it(std::forward<Op>(op), std::forward<Tuple>(args));
00094   }
00095 
00096 }
00097 
00098 #endif