Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 29.03.2022, 13:13   #1
oup_job
Новичок
Джуниор
 
Регистрация: 19.08.2019
Сообщений: 2
По умолчанию Typelist и метафункция bind вариативного шаблона. Ошибка при компиляции

Я использую `Typelist` для группировки типов.
Для него я реализовал метафункцию `tlist_find_if`, которая принимает на вход предикат
`Pred` и список типов, и возвращает тип, содержащийся в списке, если для него совпало условие.
Код:
// template <typename... Ts>
struct tlist
{
    using type = tlist;
    static constexpr size_t size() noexcept { return sizeof...(Ts); }
};
    
template <template<typename T> typename Pred, typename TList>
struct tlist_find_if_impl;

template <template<typename T> typename Pred>
struct tlist_find_if_impl<Pred, tlist<>> { using result = null_t; };

template <template<typename T> typename Pred, typename H, typename... Ts>
struct tlist_find_if_impl<Pred, tlist<H, Ts...>>
{   
    using result = typename std::conditional<Pred<H>::value, H, typename tlist_find_if_impl<Pred, tlist<Ts...> >::result>::type;
};

// Wrapper
template <template <typename T> typename Pred, typename TList>
struct tlist_find_if;

template <template <typename T> typename Pred, typename... Ts>
struct tlist_find_if<Pred, tlist<Ts...>>
{   
    using result = typename tlist_find_if_impl<Pred, tlist<Ts...> >::result;
};
Также я реализовал метафункцию `bind` для того, чтобы составлять предикаты:

Код:
template <template <typename...> typename F, typename T>
struct bind
{
    template <typename... Ts> 
    using type = F<T, Ts...>;
};
Но при ее использовании компилятор то принимает все, то выдает ошибку.

Пример без ошибки:

Код:
 
int main()
{
    // ...
    using type = tlist_find_if<bind<std::is_same, a1_t>::type, x_group >::result; // , x_group>;
    static_assert(std::is_same_v<a1_t, type>);
}
При использовании с конкретным типом ошибки нету.
А вот при использовании в шаблонной метафункции компилятор выдает ошибку.

Код:
   
template <typename T, typename GroupList>
struct group_list_2_group 
{ 
    template <typename Group>
    struct type_in_group_pred
    {   
        static constexpr bool value = std::is_same<Group, typename tlist_find_if<bind<std::is_same, T>::type, Group>::result>::value; // Ошибка!
    };  

    using group = typename tlist_find_if<type_in_group, GroupList>::result;
};

Текст ошибки:

Код:
    main2.cc:107:117: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class T> class Pred, class TList> struct tlist_find_if’
main2.cc:107:116: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class T> class Pred, class TList> struct tlist_find_if’
  107 |         static constexpr bool value = std::is_same<Group, typename tlist_find_if<bind<std::is_same, T>::type, Group>::result>::value;
      |                                                                                                                    ^
main2.cc:107:116: note:   expected a class template, got ‘bind<std::is_same, T>::type’

Т.е почему то результат bind читается компилятором как конкретный тип, а не шаблон. Но почему? В примере без ошибки всё хорошо отрабатывает.

Полный текст тестовой программы-примера для воспроизведения

Код:
    
#include <type_traits>
#include <stdio.h>:

struct a1_t { int x; };
struct a2_t { int x; };
struct b1_t { int y; };
struct b2_t { int y; };
struct c1_t { int z; };
struct c2_t { int z; };
struct null_t {};


template <typename... Ts>
struct tlist
{
   using type = tlist;
   static constexpr size_t size() noexcept { return sizeof...(Ts); }
};

template <template<typename T> typename Pred, typename TList>
struct tlist_find_if_impl; // { using result = null_t; };

template <template<typename T> typename Pred>
struct tlist_find_if_impl<Pred, tlist<>> { using result = null_t; };

template <template<typename T> typename Pred, typename H, typename... Ts>
struct tlist_find_if_impl<Pred, tlist<H, Ts...>>
{
    using result = typename std::conditional<Pred<H>::value, H, typename tlist_find_if_impl<Pred, tlist<Ts...> >::result>::type;
};

// Wrapper
template <template <typename T> typename Pred, typename TList>
struct tlist_find_if;

template <template <typename T> typename Pred, typename... Ts>
struct tlist_find_if<Pred, tlist<Ts...>>
{
    using result = typename tlist_find_if_impl<Pred, tlist<Ts...> >::result;
};

template <typename T, typename U>
struct null_t_wrap
{
    using type = typename std::conditional<std::is_same_v<null_t, T>, U, T>::type;
};

template <template <typename...> typename F, typename T>
struct bind
{
    template <typename... Ts>
    using type = F<T, Ts...>;
};

using null_group = tlist<>;
using x_group = tlist<a1_t, a2_t>;
using y_group = tlist<b1_t, b2_t>;
using group_tlist = tlist<x_group, y_group>;

template <typename T>
struct null_setter { static void set(T& t, int x) { (void)t; (void)x; printf("null setter x = %d\n", x); } };

template <typename T>
struct x_setter { static void set(T& t, int x) { t.x = x; printf("set x = %d\n", x); } };

template <typename T>
struct y_setter { static void set(T& t, int y) { t.y = y; printf("set y = %d\n", y); } };

template <typename T, typename Group>
struct group_2_setter { using setter = null_setter<T>;  };
template <typename T>
struct group_2_setter<T, x_group> { using setter = x_setter<T>; };
template <typename T>
struct group_2_setter<T, y_group> { using setter = y_setter<T>; };

template <typename T, typename Group>
struct type_2_group 
{ 
    template <typename H>
    struct type_is_same_pred
    {
        static constexpr bool value = std::is_same<T, H>::value;
    };
    // using group = typename null_t_wrap<typename tlist_find_if<type_is_same_pred, Group>::result, null_group>::type;                       
    using group = typename tlist_find_if<type_is_same_pred, Group>::result;                       
};

template <typename T, typename Group>
struct type_in_group
{
    template <typename U>
    struct is_t
    {
        static constexpr bool value = std::is_same_v<T, U>; 
    };
    static constexpr bool value = std::is_same<T, typename tlist_find_if<is_t, Group>::result>::value;
};

template <typename T, typename GroupList>
struct group_list_2_group 
{ 
    template <typename Group>
    struct type_in_group_pred
    {
        // static constexpr bool value = std::is_same<Group, typename type_2_group<T, Group>::group >::value;
        
        static constexpr bool value = std::is_same<Group, typename tlist_find_if<bind<std::is_same, T>::type, Group>::result>::value;
    };
   // using group = typename null_t_wrap<typename tlist_find_if<type_in_group_pred, GroupList>::result, null_group>::type;
//    using group = typename tlist_find_if<type_in_group_pred, GroupList>::result;
    using group = typename tlist_find_if<type_in_group_pred, GroupList>::result;
};

template <typename T, typename GroupList>
struct type_2_setter 
{
    using setter = typename group_2_setter<T, typename group_list_2_group<T, GroupList>::group>::setter; 
};

int main()
{
    a1_t a1; 
    a2_t a2;
    b1_t b1;
    b2_t b2;
    c1_t c1;
    c2_t c2;

    using is_same_as_a1_t = bind<std::is_same, a1_t>::type<a1_t>;
    static_assert(is_same_as_a1_t::value);
    
    using b2_t_setter = type_2_setter<b2_t, group_tlist>::setter;
    b2_t_setter::set(b2, 2);

    using type = tlist_find_if<bind<std::is_same, a1_t>::type, x_group >::result; // , x_group>;
    static_assert(std::is_same_v<a1_t, type>);
    static_assert(std::is_same_v<a1_t, tlist_find_if<bind<std::is_same, a1_t>::type, x_group>::result>);
}

Последний раз редактировалось oup_job; 29.03.2022 в 13:30.
oup_job вне форума Ответить с цитированием
Старый 29.03.2022, 15:06   #2
oup_job
Новичок
Джуниор
 
Регистрация: 19.08.2019
Сообщений: 2
По умолчанию

Правильное решение состоит в том, чтобы использовать ключевое слово `template` перед type

Код:
template <typename T, typename GroupList>
struct group_list_2_group 
{ 
    template <typename Group>
    struct type_in_group_pred
    {   
        static constexpr bool value = std::is_same<Group, typename tlist_find_if<bind<std::is_same, T>::template type, Group>::result>::value;
    };  

    using group = typename tlist_find_if<type_in_group, GroupList>::result;
};

Последний раз редактировалось oup_job; 29.03.2022 в 15:09.
oup_job вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Неправильное отображение сайдбара. Ошибка шаблона. niks734 WordPress и другие CMS 1 05.06.2014 14:40
получение ссылки на функцию из класса шаблона и передача ее как параметр шаблона pror0ck Общие вопросы C/C++ 7 17.06.2012 15:06
Использование файлов XLS в качестве шаблона и отображение этого шаблона в приложении Delphi? vodyara Общие вопросы Delphi 0 23.04.2012 13:13
Ошибка при компиляции... Тамарочка Общие вопросы C/C++ 3 05.12.2011 00:53
[C++] Синтаксическая ошибка в заголовке шаблона newStudent Помощь студентам 1 21.12.2010 21:02