У меня проблемы с пониманием местозаполнителей MPL.
Может кто-нибудь объяснить мне, почему этот код не компилируется?
Я ожидал бы число 0, 1 & 2 для печати, но кажется, что заполнитель не заменяется фактическим типом, когда компилятор пытается определить тип параметра шаблона по умолчанию для Wrapper.
#include <iostream>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/vector.hpp>
template <typename T> struct Traits;
template<> struct Traits<int> { typedef boost::mpl::int_<0> type; };
template<> struct Traits<char> { typedef boost::mpl::int_<1> type; };
template<> struct Traits<bool> { typedef boost::mpl::int_<2> type; };
template <typename T, typename Type=typename Traits<T>::type > struct Wrapper
{
Wrapper() { std::cout << "Value: " << Type::value << std::endl; }
T value;
};
int main()
{
typedef boost::mpl::inherit_linearly<
boost::mpl::vector<int, char, bool>,
boost::mpl::inherit<boost::mpl::_1, Wrapper<boost::mpl::_2> > >::type Object;
Object obj;
return 0;
}
Это ошибка из gcc-4.1.2 (я знаю … старый компилятор на работе)
# g++4 -I ../boost test.cpp -o test
test.cpp: In function 'int main()':
test.cpp:24: error: invalid use of undefined type 'struct Traits<mpl_::arg<2> >'
test.cpp:7: error: declaration of 'struct Traits<mpl_::arg<2> >'
test.cpp:24: error: template argument 2 is invalid
test.cpp:24: error: template argument 2 is invalid
test.cpp:24: error: template argument 2 is invalid
test.cpp:24: error: expected initializer before 'Object'
test.cpp:26: error: 'Object' was not declared in this scope
test.cpp:26: error: expected `;' before 'obj'
РЕДАКТИРОВАТЬ:
После Акорба ответ ниже я сделал вариант моей программы-примера, чтобы показать, почему предложенное им решение не соответствует моим потребностям. Это проясняет то, что я после. В этом случае я ожидаю, что текст TYPE_A, TYPE_B, TYPE_A будет напечатан. Ошибка g ++ такая же.
#include <iostream>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/vector.hpp>
enum WrapperType { TYPE_A, TYPE_B };
template <typename T> struct Traits;
template<> struct Traits<int> { typedef boost::mpl::int_<TYPE_A> type; };
template<> struct Traits<char> { typedef boost::mpl::int_<TYPE_B> type; };
template<> struct Traits<bool> { typedef boost::mpl::int_<TYPE_A> type; };
template <typename T, typename Type=typename Traits<T>::type > struct Wrapper;
template <typename T>
struct Wrapper<T, boost::mpl::int_<TYPE_A> >
{
Wrapper() : value (0) { std::cout << "TYPE_A" << std::endl; }
T value;
};
template <typename T>
struct Wrapper<T, boost::mpl::int_<TYPE_B> >
{
Wrapper() { std::cout << "TYPE_B" << std::endl; }
T value;
};
int main()
{
typedef boost::mpl::inherit_linearly<
boost::mpl::vector<int, char, bool>,
boost::mpl::inherit<boost::mpl::_1, Wrapper<boost::mpl::_2> > >::type Object;
Object obj;
return 0;
}
Это ошибка из gcc-4.5.4
# g++ -I ../boost test.cpp -o test
test.cpp: In functie ‘int main()’:
test.cpp:37:79: fout: invalid use of incomplete type ‘struct Traits<mpl_::arg<2> >’
test.cpp:9:34: fout: declaration of ‘struct Traits<mpl_::arg<2> >’
test.cpp:37:79: fout: template argument 2 is invalid
test.cpp:37:81: fout: template argument 2 is invalid
test.cpp:37:83: fout: template argument 2 is invalid
test.cpp:37:91: fout: expected initializer before ‘Object’
test.cpp:39:9: fout: ‘Object’ was not declared in this scope
test.cpp:39:16: fout: expected ‘;’ before ‘obj’
Это (частично) ошибка из clang ++ — 3.1:
test.cpp:15:50: error: implicit instantiation of undefined template 'Traits<mpl_::arg<2> >'
template <typename T, typename Type=typename Traits<T>::type > struct Wrapper;
^
test.cpp:37:57: note: in instantiation of default argument for 'Wrapper<mpl_::arg<2> >' required here
boost::mpl::inherit<boost::mpl::_1, Wrapper<boost::mpl::_2> > >::type Object;
^~~~~~~~~~~~~~~~~~~~~~~
test.cpp:9:34: note: template is declared here
template <typename T> struct Traits;
Я сделал небольшое изменение в вашем коде, разделив typedef
вызывается параметром шаблона по умолчанию в двух простых typedef
s.
Учти это:
template < typename T , typename Super_Type = Traits<T> > struct Wrapper
{
typedef typename Super_Type::type Type;
Wrapper() { std::cout << "Value: " << Type::value << std::endl; }
T value;
};
Таким образом, он компилируется. Я подозреваю, что ваше оригинальное выражение (хотя и правильное) как-то слишком сложный, чтобы быть правильно расширенным компилятором.
Хорошо … Я, кажется, взломал это …
Как часто, дополнительный уровень абстракции сделал свое дело.
Я создал класс метафункций (genWrapper), который передается в mpl :: apply1 вместе с заполнителем. Тогда метафункция вернет ожидаемый тип оболочки.
Вот результирующая программа (2-я версия).
Спасибо всем за помощь и указатели.
#include <iostream>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/vector.hpp>
enum WrapperType { TYPE_A, TYPE_B };
template <typename T> struct Traits;
template<> struct Traits<int> { typedef boost::mpl::int_<TYPE_A> type; };
template<> struct Traits<char> { typedef boost::mpl::int_<TYPE_B> type; };
template<> struct Traits<bool> { typedef boost::mpl::int_<TYPE_A> type; };
template <typename T, typename Type = typename Traits<T>::type> struct Wrapper;
template <typename T>
struct Wrapper<T, boost::mpl::int_<TYPE_A> >
{
Wrapper() : value (0) { std::cout << "TYPE_A" << std::endl; }
T value;
};
template <typename T>
struct Wrapper<T, boost::mpl::int_<TYPE_B> >
{
Wrapper() { std::cout << "TYPE_B" << std::endl; }
T value;
};
struct genWrapper
{
template <typename T>
struct apply
{
typedef Wrapper<T> type;
};
};
int main()
{
typedef boost::mpl::inherit_linearly<
boost::mpl::vector<int, char, bool>,
boost::mpl::inherit<boost::mpl::_1, boost::mpl::apply1<genWrapper, boost::mpl::_2> > >::type Object;
Object obj;
return 0;
}
Это результирующий вывод:
# g++4 -I ../boost test.cpp -o test
# ./test
TYPE_A
TYPE_B
TYPE_A