Я хотел бы вызвать функцию шаблона без аргументов для каждого типа в кортеже. Приведенный ниже код точно показывает, в чем заключается намерение.
Мое решение включает в себя создание фиктивного экземпляра 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>()
{
// ...
});
}
Мое решение состоит в том, чтобы использовать вспомогательную функцию для вывода типа. Эта вспомогательная функция принимает указатель на экземпляр 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 Конечно, Do
просто нужен аргумент функтора, который будет вызываться вместо do_something_based_on_the_type
Я не думаю, что это так просто, когда лямбда требует аргумент шаблона? template<typename F> static void Do(F func) { (func<x_Items>(), ...); }
недействителен.
@Aedoro, я добавил пример.
Вы можете передать 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>>
также следует учитывать.
Переключитесь на питон.