Обернуть С API
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 04.04.17 09:42
Оценка:
Привет,
Есть C API работу с которым хочется обернуть т.к. для использования API надо выполнить некоторые рутинные вещи. Проблема в том, параметр в виде структуры передающиеся в функцию-обёртку могут иметь, а могут не иметь некоторых полей для заполнения, следовательно, нужно выбирать алгоритмы с разными рутинами. Я осилил создание шаблона HasField для проверки наличия поля в структуре честно сперев его на SO и не разобравщись как оно работает , но не понимаю как это использовать для выбора алгоритма.
Как я себе это представляю
  Скрытый текст
далее идёт код курильшика

template<typename T, typename = void>
struct HasField_abc : std::false_type { };
template<typename T>
struct HasField_abc<T, decltype(std::declval<T>().abc, void())> : std::true_type { };

template<typename T, typename  U = HasField_abc<T>::value>
void get(T& value);

// да, я понимю что частичная специализация не применима
template<typename T, std::true_type>
void get(T& value);
{
    // поле есть
    value.abc = c_api_do_stuff();

    c_api_get(value);
}

template<typename T, std::false_type>
void get(T& value);
{
    // поля нет
    c_api_get(value);
}

Хочется увидеть код здорового человека. Нужен С++11, желательно чтобы был совместим с C++0x, т.е. поддержка не очень свежим gcc.
Sic luceat lux!
Отредактировано 04.04.2017 9:54 Kernan . Предыдущая версия . Еще …
Отредактировано 04.04.2017 9:49 Kernan . Предыдущая версия .
Re: Обернуть С API
От: kov_serg Россия  
Дата: 04.04.17 11:25
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Привет,

K>Есть C API работу с которым хочется обернуть т.к. для использования API надо выполнить некоторые рутинные вещи. Проблема в том, параметр в виде структуры передающиеся в функцию-обёртку могут иметь, а могут не иметь некоторых полей для заполнения, следовательно, нужно выбирать алгоритмы с разными рутинами. Я осилил создание шаблона HasField для проверки наличия поля в структуре честно сперев его на SO и не разобравщись как оно работает , но не понимаю как это использовать для выбора алгоритма.

А что мешает для конкретных стуктур описать?
void get(S1& s) { s.abc=c_api_s1_stuff(); c_api_get(s); }
void get(S2& s) { c_api_get(s); }
Re: Обернуть С API
От: andyp  
Дата: 04.04.17 11:26
Оценка: 4 (1)
Здравствуйте, Kernan, Вы писали:

K>Привет,

K>Есть C API работу с которым хочется обернуть т.к. для использования API надо выполнить некоторые рутинные вещи. Проблема в том, параметр в виде структуры передающиеся в функцию-обёртку могут иметь, а могут не иметь некоторых полей для заполнения, следовательно, нужно выбирать алгоритмы с разными рутинами. Я осилил создание шаблона HasField для проверки наличия поля в структуре честно сперев его на SO и не разобравщись как оно работает , но не понимаю как это использовать для выбора алгоритма.
K>Как я себе это представляю
  cut
K>
  Скрытый текст
далее идёт код курильшика

K>
K>template<typename T, typename = void>
K>struct HasField_abc : std::false_type { };
K>template<typename T>
K>struct HasField_abc<T, decltype(std::declval<T>().abc, void())> : std::true_type { };

K>template<typename T, typename  U = HasField_abc<T>::value>
K>void get(T& value);

K>// да, я понимю что частичная специализация не применима
K>template<typename T, std::true_type>
K>void get(T& value);
K>{
K>    // поле есть
K>    value.abc = c_api_do_stuff();

K>    c_api_get(value);
K>}

K>template<typename T, std::false_type>
K>void get(T& value);
K>{
K>    // поля нет
K>    c_api_get(value);
K>}
K>

K>Хочется увидеть код здорового человека. Нужен С++11, желательно чтобы был совместим с C++0x, т.е. поддержка не очень свежим gcc.

шаблоны с ограничениями?

template <typename T>
inline typename std::enable_if<HasField_abc<T>::value>::type
get(T& value)
{
...
}

template <typename T>
inline std::enable_if<!HasField_abc<T>::value>::type
get(T& value)
{
}


Если компилятор поддерживает, можешь std::enable_if_t вместо std::enable_if использовать.
Re[2]: Обернуть С API
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 04.04.17 12:35
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Здравствуйте, Kernan, Вы писали:


K>>Привет,

K>>Есть C API работу с которым хочется обернуть т.к. для использования API надо выполнить некоторые рутинные вещи. Проблема в том, параметр в виде структуры передающиеся в функцию-обёртку могут иметь, а могут не иметь некоторых полей для заполнения, следовательно, нужно выбирать алгоритмы с разными рутинами. Я осилил создание шаблона HasField для проверки наличия поля в структуре честно сперев его на SO и не разобравщись как оно работает , но не понимаю как это использовать для выбора алгоритма.

_>А что мешает для конкретных стуктур описать?

_>
_>void get(S1& s) { s.abc=c_api_s1_stuff(); c_api_get(s); }
_>void get(S2& s) { c_api_get(s); }
_>

Количество структур, у меня их за 20 штук и могут появится новые. Я бы не парился так если бы из было 2-3
Sic luceat lux!
Re[2]: Обернуть С API
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 04.04.17 12:40
Оценка:
Здравствуйте, andyp, Вы писали:

A>
A>template <typename T>
A>inline typename std::enable_if<HasField_abc<T>::value>::type
A>get(T& value)
A>{
A>...
A>}

A>template <typename T>
A>inline std::enable_if<!HasField_abc<T>::value>::type
A>get(T& value)
A>{
A>}

A>

Как это работает?

A>Если компилятор поддерживает, можешь std::enable_if_t вместо std::enable_if использовать.

Вроде поддерживает, но как оно будет потом пока не ясно.
Sic luceat lux!
Re: Обернуть С API
От: rg45 СССР  
Дата: 04.04.17 12:43
Оценка: 4 (1)
Здравствуйте, Kernan, Вы писали:

K>Привет,

K>Есть C API работу с которым хочется обернуть т.к. для использования API надо выполнить некоторые рутинные вещи. Проблема в том, параметр в виде структуры передающиеся в функцию-обёртку могут иметь, а могут не иметь некоторых полей для заполнения, следовательно, нужно выбирать алгоритмы с разными рутинами. Я осилил создание шаблона HasField для проверки наличия поля в структуре честно сперев его на SO и не разобравщись как оно работает , но не понимаю как это использовать для выбора алгоритма.
K>...
K>Хочется увидеть код здорового человека. Нужен С++11, желательно чтобы был совместим с C++0x, т.е. поддержка не очень свежим gcc.

http://ideone.com/eCjdPX
template <typename T, typename = size_t>
struct HasField_abc : std::false_type { };
 
template <typename T>
struct HasField_abc<T, decltype(sizeof(std::declval<T>().abc))> : std::true_type { };
 
template <typename T>
std::enable_if_t<HasField_abc<T>::value> get(T&)
{
    std::cout << "Has abc" << std::endl;
    // . . .
}
 
template <typename T>
std::enable_if_t<!HasField_abc<T>::value> get(T&)
{
    std::cout << "Has no abc" << std::endl;
    // . . .
}


Для не очень свежего gcc, возможно, придется использовать std::enable_if вместо std::enable_if_t, ну или определить собственный аналог для компактности кода.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 04.04.2017 12:49 rg45 . Предыдущая версия .
Re[3]: Обернуть С API
От: kov_serg Россия  
Дата: 04.04.17 13:24
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Здравствуйте, kov_serg, Вы писали:


_>>Здравствуйте, Kernan, Вы писали:


K>>>Привет,

K>>>Есть C API работу с которым хочется обернуть т.к. для использования API надо выполнить некоторые рутинные вещи. Проблема в том, параметр в виде структуры передающиеся в функцию-обёртку могут иметь, а могут не иметь некоторых полей для заполнения, следовательно, нужно выбирать алгоритмы с разными рутинами. Я осилил создание шаблона HasField для проверки наличия поля в структуре честно сперев его на SO и не разобравщись как оно работает , но не понимаю как это использовать для выбора алгоритма.

_>>А что мешает для конкретных стуктур описать?

_>>
_>>void get(S1& s) { s.abc=c_api_s1_stuff(); c_api_get(s); }
_>>void get(S2& s) { c_api_get(s); }
_>>

K>Количество структур, у меня их за 20 штук и могут появится новые. Я бы не парился так если бы из было 2-3
Невижу проблем 20 не 20000. И потом можно сделать генератор.
Re[3]: Обернуть С API
От: andyp  
Дата: 04.04.17 13:56
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Здравствуйте, andyp, Вы писали:


A>>
A>>template <typename T>
A>>inline typename std::enable_if<HasField_abc<T>::value>::type
A>>get(T& value)
A>>{
A>>...
A>>}

A>>template <typename T>
A>>inline std::enable_if<!HasField_abc<T>::value>::type
A>>get(T& value)
A>>{
A>>}

A>>

K>Как это работает?

http://en.cppreference.com/w/cpp/language/sfinae
Если есть член, компилятор сгенерит одно определение функции, а второе не сможет и выкинет функцию из множества перегрузок. Ну и если нет члена — то будет обратное, только выкинет первое определение.
Re[3]: Обернуть С API
От: rg45 СССР  
Дата: 04.04.17 15:27
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Как это работает?


Погугли по аббревиатуре SFINAE (Substitution Failure Is Not An Error). Мы разобрали только один частный случай применения этой идиомы, тогда как сценариев ее исползования существенно больше.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: Обернуть С API
От: swingus  
Дата: 04.04.17 20:13
Оценка: 4 (1) +1
Из соображений скорости компиляции разумнее сделать tag dispatch'ем:


template<typename T>
void get(T& value, std::true_type);
{
    // поле есть
    value.abc = c_api_do_stuff();

    c_api_get(value);
}

template<typename T>
void get(T& value, std::false_type);
{
    // поля нет
    c_api_get(value);
}

template<typename T>
void get(T& value)
{
    get(value, HasField_abc<T>{});
}


Здравствуйте, Kernan, Вы писали:
Re[2]: Обернуть С API
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 05.04.17 08:27
Оценка:
Здравствуйте, swingus, Вы писали:

S>Из соображений скорости компиляции разумнее сделать tag dispatch'ем:


S>Здравствуйте, Kernan, Вы писали:

Скорее всего как-то так и сделаю. Проблема в том, что решение от rg45 традиционно не взлетело.
Sic luceat lux!
Re[3]: Обернуть С API
От: kov_serg Россия  
Дата: 05.04.17 09:57
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Здравствуйте, swingus, Вы писали:


S>>Из соображений скорости компиляции разумнее сделать tag dispatch'ем:


S>>Здравствуйте, Kernan, Вы писали:

K>Скорее всего как-то так и сделаю. Проблема в том, что решение от rg45 традиционно не взлетело.

На обычном C++ можно как-то так написать
#include <stdio.h>

#define MAYSET(name) \
        template<class T> class Has_##name { \
            struct A { int name; }; \
            struct B : T,A {}; \
            template<typename C,C> struct D; \
            template<class C> static double test(D<int A::*,&C::name>*); \
            template<class C> static char test(...); \
    public: \
            enum { value = sizeof(test<B>(0))==sizeof(char) }; \
    }; \
    template<class T,class V> void mayset_##name(T *t,V v,char(*)[!Has_##name<T>::value]=0) {} \
    template<class T,class V> void mayset_##name(T *t,V v,char(*)[Has_##name<T>::value]=0) { \
        t->name=v; \
        printf("set "#name"=%d\n",(int)v); /* для проверки */ \
    }

MAYSET(x)

struct A { int x; } a[1];
struct B { int y; } b[1];

int main(int argc,char**argv) {
    mayset_x(a,10);
    mayset_x(b,20);
    return 0;
}
Re[3]: Обернуть С API
От: rg45 СССР  
Дата: 05.04.17 11:19
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Проблема в том, что решение от rg45 традиционно не взлетело.


Что именно не взлетело, ты пытался разобраться? Вот это же решение с минимальными изменениями нормально работает тоже на gcc в рамках С++11: http://cpp.sh/7sen.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 05.04.2017 11:36 rg45 . Предыдущая версия .
Re[4]: Обернуть С API
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 05.04.17 11:33
Оценка:
Здравствуйте, rg45, Вы писали:

R>Что именно не взлетело?

В 11 нет enable_if_t (я нашёл реализацию на SO от нашего коллеги Abyx), но даже после этого компилятор выкидывает из поиска не то, что нужно. Может это бага компилятора.
Sic luceat lux!
Re[5]: Обернуть С API
От: rg45 СССР  
Дата: 05.04.17 11:41
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Здравствуйте, rg45, Вы писали:


R>>Что именно не взлетело?

K>В 11 нет enable_if_t (я нашёл реализацию на SO от нашего коллеги Abyx), но даже после этого компилятор выкидывает из поиска не то, что нужно. Может это бага компилятора.

Так я тебе об этом сразу написал в том же сообщении:

Для не очень свежего gcc, возможно, придется использовать std::enable_if вместо std::enable_if_t, ну или определить собственный аналог для компактности кода.


Релизация enable_if_t тривиальна:

template <bool cond, typename type = void>
using enable_if_t = typename std::enable_if<cond, type>::type;
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 05.04.2017 11:41 rg45 . Предыдущая версия .
Re[5]: Обернуть С API
От: rg45 СССР  
Дата: 05.04.17 12:21
Оценка:
Здравствуйте, Kernan, Вы писали:

K>...но даже после этого компилятор выкидывает из поиска не то, что нужно. Может это бага компилятора.


Это gcc? Какая версия?
--
Не можешь достичь желаемого — пожелай достигнутого.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.