cách quá muộn, tôi biết, nhưng những gì về vấn đề này:
// MSVC++ 2010 SP1 x86
// boost 1.53
#include <tuple>
#include <memory>
// test
#include <iostream>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/begin.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/unpack_args.hpp>
#include <boost/mpl/apply.hpp>
// test
#include <boost/range/algorithm/for_each.hpp>
/*! \internal
*/
namespace detail
{
/*! \internal
*/
namespace runtime_template
{
/*! \internal
fwd
*/
template <
typename Template
, typename Types
, typename Map // top level map iterator
, typename LastMap // top level map iterator
, int Index
, bool Done = std::is_same<Map, LastMap>::value
>
struct apply_recursive_t;
/*! \internal
fwd
*/
template <
typename Template
, typename Types
, typename Map // top level map iterator
, typename LastMap // top level map iterator
, typename First
, typename Last
, int Index
, bool Enable = !std::is_same<First, Last>::value
>
struct apply_mapping_recursive_t;
/*! \internal
run time compare key values + compile time push_back on \a Types
*/
template <
typename Template
, typename Types
, typename Map // top level map iterator
, typename LastMap // top level map iterator
, typename First
, typename Last
, int Index // current argument
, bool Enable /* = !std::is_same<First, Last>::value */
>
struct apply_mapping_recursive_t
{
typedef void result_type;
template <typename TypeIds, typename T>
inline static void apply(const TypeIds& typeIds, T&& t)
{ namespace mpl = boost::mpl;
typedef typename mpl::deref<First>::type key_value_pair;
typedef typename mpl::first<key_value_pair>::type typeId; // mpl::int
if (typeId::value == std::get<Index>(typeIds))
{
apply_recursive_t<
Template
, typename mpl::push_back<
Types
, typename mpl::second<key_value_pair>::type
>::type
, typename mpl::next<Map>::type
, LastMap
, Index + 1
>::apply(typeIds, std::forward<T>(t));
}
else
{
apply_mapping_recursive_t<
Template
, Types
, Map
, LastMap
, typename mpl::next<First>::type
, Last
, Index
>::apply(typeIds, std::forward<T>(t));
}
}
};
/*! \internal
mapping not found
\note should never be invoked, but must compile
*/
template <
typename Template
, typename Types
, typename Map // top level map iterator
, typename LastMap // top level map iterator
, typename First
, typename Last
, int Index
>
struct apply_mapping_recursive_t<
Template
, Types
, Map
, LastMap
, First
, Last
, Index
, false
>
{
typedef void result_type;
template <typename TypeIds, typename T>
inline static void apply(const TypeIds& /* typeIds */, T&& /* t */)
{
BOOST_ASSERT(false);
}
};
/*! \internal
push_back on \a Types template types recursively
*/
template <
typename Template
, typename Types
, typename Map // top level map iterator
, typename LastMap // top level map iterator
, int Index
, bool Done /* = std::is_same<Map, LastMap>::value */
>
struct apply_recursive_t
{
typedef void result_type;
template <typename TypeIds, typename T>
inline static void apply(const TypeIds& typeIds, T&& t)
{ namespace mpl = boost::mpl;
typedef typename mpl::deref<Map>::type Mapping; // [key;type] pair vector
apply_mapping_recursive_t<
Template
, Types
, Map
, LastMap
, typename mpl::begin<Mapping>::type
, typename mpl::end<Mapping>::type
, Index
>::apply(typeIds, std::forward<T>(t));
}
};
/*! \internal
done! replace mpl placeholders of \a Template with the now complete \a Types
and invoke result
*/
template <
typename Template
, typename Types
, typename Map
, typename LastMap
, int Index
>
struct apply_recursive_t<
Template
, Types
, Map
, LastMap
, Index
, true
>
{
typedef void result_type;
template <typename TypeIds, typename T>
inline static void apply(const TypeIds& /* typeIds */, T&& t)
{ namespace mpl = boost::mpl;
typename mpl::apply<
mpl::unpack_args<Template>
, Types
>::type()(std::forward<T>(t));
}
};
/*! \internal
helper functor to be used with invoke_runtime_template()
\note cool: mpl::apply works with nested placeholders types!
*/
template <typename Template>
struct make_runtime_template_t
{
typedef void result_type;
template <typename Base>
inline void operator()(std::unique_ptr<Base>* base) const
{
base->reset(new Template());
}
};
} // namespace runtime_template
} // namespace detail
/*! \brief runtime template parameter selection
\param Template functor<_, ...> placeholder expression
\param Maps mpl::vector<mpl::vector<mpl::pair<int, type>, ...>, ...>
\param Types std::tuple<int, ...> type ids
\param T functor argument type
\note all permutations must be compilable (they will be compiled of course)
\note compile time: O(n!) run time: O(n)
\sa invoke_runtime_template()
\author slow
*/
template <
typename Template
, typename Map
, typename Types
, typename T
>
inline void invoke_runtime_template(const Types& types, T&& t)
{ namespace mpl = boost::mpl;
BOOST_STATIC_ASSERT(mpl::size<Map>::value == std::tuple_size<Types>::value);
detail::runtime_template::apply_recursive_t<
Template
, mpl::vector<>
, typename mpl::begin<Map>::type
, typename mpl::end<Map>::type
, 0
>::apply(types, std::forward<T>(t));
}
/*! \sa invoke_runtime_template()
*/
template <
typename Template
, typename Map
, typename Base
, typename Types
>
inline void make_runtime_template(const Types& types, std::unique_ptr<Base>* base)
{
invoke_runtime_template<
detail::runtime_template::make_runtime_template_t<Template>
, Map
>(types, base);
}
/*! \overload
*/
template <
typename Base
, typename Template
, typename Map
, typename Types
>
inline std::unique_ptr<Base> make_runtime_template(const Types& types)
{
std::unique_ptr<Base> result;
make_runtime_template<Template, Map>(types, &result);
return result;
}
////////////////////////////////////////////////////////////////////////////////
namespace mpl = boost::mpl;
using mpl::_;
class MyClassInterface {
public:
virtual ~MyClassInterface() {}
virtual double foo(double) = 0;
};
template <int P1, int P2, int P3>
class MyClass
: public MyClassInterface {
public:
double foo(double /*a*/) {
// complex computation dependent on P1, P2, P3
std::wcout << typeid(MyClass<P1, P2, P3>).name() << std::endl;
return 42.0;
}
// more methods and fields (dependent on P1, P2, P3)
};
// wrapper for transforming types (mpl::int) to values
template <typename P1, typename P2, typename P3>
struct MyFactory
{
inline void operator()(std::unique_ptr<MyClassInterface>* result) const
{
result->reset(new MyClass<P1::value, P2::value, P3::value>());
}
};
template <int I>
struct MyConstant
: boost::mpl::pair<
boost::mpl::int_<I>
, boost::mpl::int_<I>
> {};
std::unique_ptr<MyClassInterface> Factor(const std::tuple<int, int, int>& constants) {
typedef mpl::vector<
MyConstant<0>
, MyConstant<1>
, MyConstant<2>
, MyConstant<3>
// ...
> MyRange;
std::unique_ptr<MyClassInterface> result;
invoke_runtime_template<
MyFactory<_, _, _>
, mpl::vector<MyRange, MyRange, MyRange>
>(constants, &result);
return result;
}
int main(int /*argc*/, char* /*argv*/[])
{
typedef std::tuple<int, int, int> Tuple;
const Tuple Permutations[] =
{
std::make_tuple(0, 0, 0)
, std::make_tuple(0, 0, 1)
, std::make_tuple(0, 1, 0)
, std::make_tuple(0, 1, 1)
, std::make_tuple(1, 0, 0)
, std::make_tuple(1, 2, 3)
, std::make_tuple(1, 1, 0)
, std::make_tuple(1, 1, 1)
// ...
};
boost::for_each(Permutations, [](const Tuple& constants) { Factor(constants)->foo(42.0); });
return 0;
}
Tôi thực sự muốn biết lý do vượt ra ngoài câu hỏi đó. Bạn có thể giải thích cho chúng tôi những gì bạn đang cố gắng đạt được bằng cách sử dụng cấu trúc kỳ lạ này không? –
Có một thuật toán rất lớn có thể được tham số hóa bằng cách sử dụng các tham số nguyên mẫu. Phụ thuộc vào các tham số, biên dịch tạo ra một số mã được tối ưu hóa cao. Bây giờ tôi muốn có thể sử dụng những "phiên bản" khác nhau từ bên ngoài mà không quan tâm đến việc triển khai của chúng và bằng cách chỉ định các tham số khi chạy theo cách do người dùng giám sát. Mặc dù ứng dụng này, điều này cũng có nghĩa là một câu hỏi lý thuyết trong sự tò mò tinh khiết. – Danvil
Lưu ý rằng do sự khởi tạo của một số lượng lớn các chuyên ngành có thể có, kích thước khổng lồ có thể thực thi được về mặt kỹ thuật có thể đi ngược lại với các tối ưu hóa của bạn một cách hiệu quả. Mã lớn thường có nghĩa là mã chậm, đặc biệt là trong sự hiện diện của các mẫu phân nhánh không đều. (như mọi khi, hồ sơ để biết những gì đang xảy ra) –