Russian Qt Forum

Программирование => С/C++ => Тема начата: Eugene Efremov от Апрель 09, 2008, 01:35



Название: SFINAE для методов шаблонных классов
Отправлено: Eugene Efremov от Апрель 09, 2008, 01:35
Имеем следующий пример неработающего кода:

Код:
struct foo1 { typedef int val; };
struct foo2 { };

template <class foo> struct bar
{
typename foo::val f() {return 10; }
// other...
};

int main()
{
bar<foo1> f1;
bar<foo2> f2; // error: no type named `val' in `struct foo2'

int i = f1.f();
//f2::f newer used...
}

Есть идеи, как можно поизвращаться с enable_if и ему подобными, чтобы заставить это дело компиляться, игнорируя отсутствие foo::val для bar<foo2>?


Название: Re: SFINAE для методов шаблонных классов
Отправлено: Tonal от Апрель 09, 2008, 08:56
Код:
#include <iostream>

struct yes {
  char dummy;
};
struct no {
  yes dummy[2];
};         

//Распознование, определён ли в классе typedef val
template <class T>
struct has_val {
  template <class Y>
  struct check {
    typedef yes res;
  };
  template <class U>
  static typename check<typename U::val>::res test_val(const U*);
  static no test_val(...);

  enum {value = sizeof(yes) == sizeof(test_val((T*)0))};
};

template <class foo>
struct bar {
  //Выбор возвращаемого значения и selector-а
  template <class T, bool enable>
  struct type_select {
    typedef typename T::val type;
    typedef const T* selector;
  };

  //Возвращаемое значения и selector по умолчанию
  template <class T>
  struct type_select<T, false> {
    typedef long type;
    typedef const void* selector;
  };

  typedef typename type_select<foo, has_val<foo>::value>::type ret_type;
  typedef typename type_select<foo, has_val<foo>::value>::selector selector;

  //Основная реализация
  ret_type f(const foo*) {
    return 10;
  }

  //Реализация по умолчанию
  ret_type f(const void*) {
    return 5;
  }

  //Диспетчер
  ret_type f() {
    return f((selector)0);
  }
  // other...
};

//Тестовый пример
using std::cout;
using std::endl;

struct foo1 {
  typedef int val;
};

struct foo2 {
};

int main() {
  bar<foo1> f1;
  bar<foo2> f2;
 
  cout<<f1.f()<<endl;
  cout<<f2.f()<<endl;
}
На boost::enable_if сам переводи. :)

P.S. Блин, насколько всё же проще писать подобное на Haskell, где встроенное сопоставление с образцом...


Название: Re: SFINAE для методов шаблонных классов
Отправлено: Eugene Efremov от Апрель 09, 2008, 19:09
Код:
[...skip...]

Спасибо!

P.S. Блин, насколько всё же проще писать подобное на Haskell, где встроенное сопоставление с образцом...

Ну дык ёлы-палы... Увидев конструкции, порождаемые этим самозародившимся функциональным франкенштейном, волей-неволей задумаешься — какой казни следует предать Страуструпа и КО а строит ли оно того... :-)