Полиморфизм на основе typeded
От:
ilejn
Дата: 24.06.11 13:07
Оценка:
Здравствуйте.
Хочется научиться вызывать специфический вариант некоторой функции для
особым образом промаркированных структур.
Маркером выступает typedef.
Беда в том, что вот этот код
==
template <typename T>
struct NotPresent
{
typedef int raw_mark;
};
template <typename T>
struct NotPresent<typename T::raw_mark>
{
};
template <typename T>
void
ftag(const T& arg, typename NotPresent<T>::raw_mark dummy = 0)
{
std::cout << "simple" << std::endl;
}
template <typename T>
void
ftag(const T&, typename T::raw_mark dummy = 0)
{
std::cout << "raw marked" << std::endl;
}
struct BMarked
{
typedef int raw_mark;
int field;
};
struct CNotMarked
{
int field;
};
int
main(int, char**)
{
int a;
BMarked b;
CNotMarked c;
ftag<int>(a);
ftag<BMarked>(b);
ftag<CNotMarked>(c);
}
==
всем хорош, но не компилируется с рассказом про неоднозначность вызова ftag для BMarked.
Абсолютно не понимаю, откуда берется NotPresent<T>::raw_mark для BMarked.
Re: Полиморфизм на основе typeded
От:
ilejn
Дата: 24.06.11 13:29
Оценка:
Если чуть-чуть локализовать проблему, то нужно придумать волшебство, чтобы
различать "default" и "marked"
Код ниже выводит default/pointer/default, вместо желаемых default/pointer/marked
==
template <typename T>
struct Default
{
void
f()
{
std::cout << "default" << std::endl;
}
};
template <typename T>
struct Default<T*>
{
void
f()
{
std::cout << "pointer" << std::endl;
}
};
template <typename T>
struct Default<typename T::mark>
{
void
f()
{
std::cout << "marked" << std::endl;
}
};
struct Marked
{
typedef int mark;
};
int
main(int, char**)
{
Default<int> a;
Default<int*> b;
Default<Marked> c;
a.f();
b.f();
c.f();
}
==
Re[2]: Полиморфизм на основе typeded
Здравствуйте, ilejn.
Прежде всего хочу спросить, почему именно int в typedef? Я бы сделал нечто вроде:
struct enable_mark
{
enum { value = true };
};
struct Marked
{
typedef enable_mark mark;
};
Потом же можно проверить марку через enable_if.
template <typename T, typename Enable = void >
struct Default
{
void f()
{
std::cout << "default" << std::endl;
}
};
template <typename T>
struct Default<T*>
{
void f()
{
std::cout << "pointer" << std::endl;
}
};
template <typename T>
struct Default<T, typename boost::enable_if<typename T::mark>::type>
{
void f()
{
std::cout << "marked" << std::endl;
}
};
Для тех, кто смущен предрассудками и не станет использовать boost:
template <bool B, typename T = void >
struct enable_if_c
{
typedef T type;
};
template <typename T>
struct enable_if_c<false , T>
{};
template <typename Cond, typename T = void >
struct enable_if : public enable_if_c<Cond::value, T>
{};
Re: Полиморфизм на основе typeded
с использованием boost как-то так можно сделать:
#include <boost/current_function.hpp>
#include <boost/mpl/filter_view.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/lambda.hpp>
#include <boost/mpl/pop_front.hpp>
#include <boost/utility/enable_if.hpp>
#include <iostream>
/// Check if type `mark' present in T
template <typename T>
class has_mark
{
template <typename U>
struct has_get_mark_introspect
{
template <typename V>
static boost::mpl::aux::no_tag test(...);
template <typename V>
static boost::mpl::aux::yes_tag test(typename V::mark* = 0);
static const bool value = sizeof (test<U>(0)) == sizeof (boost::mpl::aux::yes_tag);
typedef boost::mpl::bool_<value> type;
};
public :
static const bool value = has_get_mark_introspect<T>::value;
typedef typename has_get_mark_introspect<T>::type type;
};
/// Some marked struture
struct has_mark_t {
typedef int mark;
};
/// Some not marked structure
struct has_no_mark_t {
};
/// Function foo to be called for marked structures
template <typename T>
typename boost::enable_if<
has_mark<T>
>::type foo(const T&)
{
std::cout << "calling foo for type w/ 'mark' type present\n" ;
}
/// Function foo for other (not marked) types
template <typename T>
typename boost::disable_if<
has_mark<T>
>::type foo(const T&)
{
std::cout << "calling foo for type w/o 'mark' type present\n" ;
}
int main()
{
std::cout << has_mark<has_mark_t>::type::value << std::endl;
std::cout << has_mark<has_no_mark_t>::type::value << std::endl;
foo(has_mark_t());
foo(has_no_mark_t());
return 0;
}
zaufi@gentop /work/tests $ g++ -o has_mark has_mark.cc
zaufi@gentop /work/tests $ ./has_mark
1
0
calling foo for type w/ 'mark' type present
calling foo for type w/o 'mark' type present
zaufi@gentop /work/tests $ g++ --version | head -n 1
g++ (Gentoo 4.5.2 p1.0, pie-0.4.5) 4.5.2
Re[2]: Полиморфизм на основе typeded
От:
zaufi
Дата: 24.06.11 15:32
Оценка:
ой! пример делал из другого кода... там не нужно столько #include... достаточно вот этого... )
Z>#include <boost/mpl/bool .hpp>
#include <boost/mpl/aux_/yes_no.hpp>
Z>#include <boost/utility/enable_if.hpp>
Z>#include <iostream>
...
Z>
Re[3]: Полиморфизм на основе typedef
От:
ilejn
Дата: 27.06.11 06:40
Оценка:
Здравствуйте, wander, Вы писали:
W>Здравствуйте, ilejn.
W>Прежде всего хочу спросить, почему именно int в typedef?
В примере использован int исключительно по скудости моей фантазии.
На самом деле, это не int, а некий сложный тип.
Вносить какие-то изменения в структуры данных, которые мы хотим узнавать в лицо и
обрабатывать некоторым специальным образом, не предполагается.
Re[2]: Полиморфизм на основе typeded
От:
ilejn
Дата: 27.06.11 06:48
Оценка:
Здравствуйте, zaufi, Вы писали:
Z>с использованием boost как-то так можно сделать:
О, да, почему-то я не сообразил, как эта техника применима для проверки наличия типа.
Спасибо!
Пока на собственное сообщение не было ответов, его можно удалить.
Удалить