Полиморфизм на основе 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
От: wander  
Дата: 24.06.11 14:59
Оценка: 1 (1)
Здравствуйте, 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
От: zaufi Земля  
Дата: 24.06.11 15:28
Оценка: 2 (1)
с использованием 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 как-то так можно сделать:


О, да, почему-то я не сообразил, как эта техника применима для проверки наличия типа.

Спасибо!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.