Вызов функции-шаблона с типами в кортеже (не значениями)

Я хотел бы вызвать функцию шаблона без аргументов для каждого типа в кортеже. Приведенный ниже код точно показывает, в чем заключается намерение.

Мое решение включает в себя создание фиктивного экземпляра DataGroup(). Я хотел бы избежать этого, так как типы могут не иметь конструктора по умолчанию.

Вместо этого я попытался использовать std::declval<DataGroup>(), это приводит к 'std::declval': Symbol involving type with internal linkage not defined (в msvc).

#pragma once
#include <tuple>

template<typename T>
void do_something_based_on_the_type()
{
    // ...
}

template<template <typename...> typename Tuple, typename... Ts>
void do_something_based_on_the_types_in_a_tuple(Tuple<Ts...>)
{
    (do_something_based_on_the_type<Ts>(), ...);
}

void some_code()
{
    struct Dataset1 {};
    struct Dataset2 {};
    struct Dataset3 {};
    using DataGroup = std::tuple<Dataset1, Dataset2, Dataset3>;

    do_something_based_on_the_types_in_a_tuple(DataGroup()); // -> ugly? requires a dummy instantiation of the tuple
}



Мое предпочтительное решение, основанное на двух ответах вместе:

namespace internal
{

template<template <typename...> typename Tuple, typename TemplateFunc, typename... Ts>
void call_per_type_in_tuple(std::type_identity<Tuple<Ts...>>, TemplateFunc f)
{
    (f.template operator () < Ts > (), ...);
}

}

template<typename Tuple, typename TemplateFunc>
void call_foreach_tuple_type(TemplateFunc f)
{
    internal::call_per_type_in_tuple(std::type_identity<Tuple>(), std::forward<TemplateFunc>(f));
}

void example()
{
    struct Dataset1 {};
    struct Dataset2 {};
    struct Dataset3 {};
    using DataGroup = std::tuple<Dataset1, Dataset2, Dataset3>;

    call_foreach_tuple_type<DataGroup>([]<typename T>()
    {
        // ...
    });
}

Переключитесь на питон.

Yves Daoust 02.02.2023 13:38
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
98
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Мое решение состоит в том, чтобы использовать вспомогательную функцию для вывода типа. Эта вспомогательная функция принимает указатель на экземпляр DataGroup и использует его для вывода типов в кортеже.

template<typename T>
void do_something_based_on_the_type()
{
    // ...
}

template<typename T>
void do_something_based_on_the_types_in_a_tuple_helper(T* dataGroup)
{
    std::apply([](auto&&... args){ (do_something_based_on_the_type<decltype(args)>(), ...); }, *dataGroup);
}

void some_code()
{
    struct Dataset1 {};
    struct Dataset2 {};
    struct Dataset3 {};
    using DataGroup = std::tuple<Dataset1, Dataset2, Dataset3>;

    DataGroup dataGroup;
    do_something_based_on_the_types_in_a_tuple_helper(&dataGroup);
}

Вариант со специализацией шаблона класса:

#include <tuple>

template<typename T>
void do_something_based_on_the_type()
{
    // ...
}

template<typename x_Tuple>
class t_ForEachItem;

template<typename... x_Items>
class t_ForEachItem<::std::tuple<x_Items...>>
{
    public: static void
    Do(){ (do_something_based_on_the_type<x_Items>(), ...); }
};

void some_code()
{
    struct Dataset1 {};
    struct Dataset2 {};
    struct Dataset3 {};
    using DataGroup = std::tuple<Dataset1, Dataset2, Dataset3>;

    t_ForEachItem<DataGroup>::Do();
}

Его также можно использовать с вызовом функции:

template<typename x_Tuple>
void do_something_based_on_the_types_in_a_tuple()
{
   t_ForEachItem<x_Tuple>::Do();
}
...
do_something_based_on_the_types_in_a_tuple<DataGroup>();

Общий вариант:

#include <tuple>

template<typename x_Tuple>
class t_ForEachItem;

template<typename... x_Items>
class t_ForEachItem<::std::tuple<x_Items...>>
{
    public: template<typename x_Fun> static void
    Do(x_Fun fun){ (fun.template operator ()<x_Items>(), ...); }
};

void some_code()
{
    struct Dataset1 {};
    struct Dataset2 {};
    struct Dataset3 {};
    using DataGroup = std::tuple<Dataset1, Dataset2, Dataset3>;

    t_ForEachItem<DataGroup>::Do([]<typename T>(){});
}

онлайн компилятор

Есть ли шанс на общую версию, которая позволяет это: t_ForEachItem<DataGroup>()::Do([]<typename T>(){ /*...*/ });? передача лямбда-шаблона с типом?

Aedoro 02.02.2023 13:21

@Aedoro Конечно, Do просто нужен аргумент функтора, который будет вызываться вместо do_something_based_on_the_type

user7860670 02.02.2023 13:23

Я не думаю, что это так просто, когда лямбда требует аргумент шаблона? template<typename F> static void Do(F func) { (func<x_Items>(), ...); } недействителен.

Aedoro 02.02.2023 13:32

@Aedoro, я добавил пример.

user7860670 02.02.2023 13:37
Ответ принят как подходящий

Вы можете передать std::type_identity, который всегда конструируется по умолчанию.

#include <type_traits>

template<template <typename...> typename Tuple, typename... Ts>
void do_something_based_on_the_types_in_a_tuple(std::type_identity<Tuple<Ts...>>)
{
    (do_something_based_on_the_type<Ts>(), ...);
}

using DataGroup = std::tuple<Dataset1, Dataset2, Dataset3>;
do_something_based_on_the_types_in_a_tuple(std::type_identity<DataGroup>());
std::tuple<std::identity<T1>, std::identity<T2>> также следует учитывать.
Jarod42 02.02.2023 18:45

Другие вопросы по теме