다른 유형에 대한 반복
다음 코드가 주어집니다.
struct Window{
void show();
//stuff
}w1, w2, w3;
struct Widget{
void show();
//stuff
}w4, w5, w6;
struct Toolbar{
void show();
//stuff
}t1, t2, t3;
show
여러 항목을 원합니다 .
for (auto &obj : {w3, w4, w5, t1})
obj.show();
그러나 이것은 std::initializer_list<T>
in- for
loop가 추론 할 수없고 T
실제로 T
적합 하지 않기 때문에 컴파일되지 않습니다 . 필요한 코드의 양과 불필요한 런타임 오버 헤드로 인해 유형 삭제 유형을 만들고 싶지 않습니다. obj
개념 목록의 모든 항목에 대해 개별적으로 유형 이 추론 되도록 루프를 올바르게 작성하려면 어떻게해야 합니까?
최신 C ++에서는 폴드 표현식을 사용 하여 멤버 함수를 적용하는 이기종 인수를 "통과"합니다.
auto Printer = [](auto&&... args) {
(args.show(), ...);
};
Printer(w1, w2, w3, w4, w5, w6, t1, t2, t3);
내 블로그 에서 자세한 내용을 읽을 수 있습니다.
boost :: fusion은 굉장하지만 oldskool-C ++ 03의 결함을 충족시킵니다.
C ++ 11의 가변 템플릿 확장을 구출하세요!
#include <iostream>
struct Window{
void show() {
std::cout << "Window\n";
}
//stuff
}w1, w2, w3;
struct Widget{
void show() {
std::cout << "Widget\n";
}
//stuff
}w4, w5, w6;
struct Toolbar{
void show()
{
std::cout << "Toolbar\n";
}
//stuff
}t1, t2, t3;
template<class...Objects>
void call_show(Objects&&...objects)
{
using expand = int[];
(void) expand { 0, ((void)objects.show(), 0)... };
}
auto main() -> int
{
call_show(w3, w4, w5, t1);
return 0;
}
예상 출력 :
Window
Widget
Widget
Toolbar
다른보다 일반적인 방법 (c ++ 14 필요) :
// note that i have avoided a function names that look like
// one in the standard library.
template<class Functor, class...Objects>
void for_all(Functor&& f, Objects&&... objects)
{
using expand = int[];
(void) expand { 0, (f(std::forward<Objects>(objects)), 0)... };
}
이렇게 불렀습니다.
for_all([](auto& thing) { thing.show(); }, w3, w4, w5, t1);
또 다른 옵션은 boost::tuple
또는 std::tuple
및 boost::fusion::for_each
알고리즘 을 사용 하는 것입니다.
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/adapted/boost_tuple.hpp>
boost::fusion::for_each(
boost::tie(w1, w2, w3, w4, w5, w6, t1, t2, t3), // by reference, not a copy
[](auto&& t) { t.show(); }
);
호기심에서 Richard Hodges의 방법으로 생성 된 어셈블리 출력을 위와 비교했습니다. 로 gcc-4.9.2 -Wall -Wextra -std=gnu++14 -O3 -march=native
제조 된 어셈블리 코드와 동일하다.
https://stackoverflow.com/a/6894436/3484570을 기반으로 이것은 추가 기능, 부스트 또는 상속을 생성하지 않고 작동합니다.
머리글:
#include <tuple>
#include <utility>
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(const std::tuple<Tp...> &, FuncT) // Unused arguments are given no names.
{ }
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(const std::tuple<Tp...>& t, FuncT f)
{
f(std::get<I>(t));
for_each<I + 1, FuncT, Tp...>(t, f);
}
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> &&, FuncT) // Unused arguments are given no names.
{ }
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...>&& t, FuncT f)
{
f(std::get<I>(t));
for_each<I + 1, FuncT, Tp...>(std::move(t), f);
}
.cpp :
struct Window{
void show(){}
//stuff
}w1, w2, w3;
struct Widget{
void show(){}
//stuff
}w4, w5, w6;
struct Toolbar{
void show(){}
//stuff
}t1, t2, t3;
int main() {
for_each(std::tie(w3, w4, w5, t1), [](auto &obj){
obj.show();
});
}
Window
, Widget
및 Toolbar
공유 공통 인터페이스, 당신은 추상 클래스를 생성하고 다른 클래스가 상속 할 수 있도록 :
struct Showable {
virtual void show() = 0; // abstract method
};
struct Window: Showable{
void show();
//stuff
}w1, w2, w3;
struct Widget: Showable{
void show();
//stuff
}w4, w5, w6;
struct Toolbar: Showable{
void show();
//stuff
}t1, t2, t3;
그런 다음에 대한 포인터 배열을 만들고 그 Showable
위에 반복 할 수 있습니다.
int main() {
Showable *items[] = {&w3, &w4, &w5, &t1};
for (auto &obj : items)
obj->show();
}
I recommend Boost.Hana, which IMHO is the best and most flexible template meta-programming library available.
#include <boost/hana/ext/std/tuple.hpp>
#include <boost/hana.hpp>
namespace hana = boost::hana;
hana::for_each(std::tie(w3, w4, w5, t1), [](auto& obj) { obj.show(); });
I think boost::variant
is worth mentioning. All the more it has chances to become std::variant
in C++17.
int main()
{
std::vector<boost::variant<Window*, Widget*, Toolbar*>> items = { &w1, &w4, &t1 };
for (const auto& item : items)
{
boost::apply_visitor([](auto* v) { v->show(); }, item);
}
return 0;
}
A late answer but here is general solution with C++14 which works like the boost::fusion::for_each
but doesn't require Boost:
#include <tuple>
namespace detail {
template<typename Tuple, typename Function, std::size_t... Is>
void tuple_for_each_impl(Tuple&& tup, Function&& fn, std::index_sequence<Is...>) {
using dummy = int[];
static_cast<void>(dummy {
0, (static_cast<void>(fn(std::get<Is>(std::forward<Tuple>(tup)))), 0)...
});
}
}
template<typename Function, typename... Args>
void tuple_for_each(std::tuple<Args...>&& tup, Function&& fn) {
detail::tuple_for_each_impl(std::forward<std::tuple<Args...>>(tup),
std::forward<Function>(fn), std::index_sequence_for<Args...>{});
}
int main() {
tuple_for_each(std::tie(w1, w2, w3, w4, w5, w6, t1, t2, t3), [](auto&& arg) {
arg.show();
});
}
If you want to achieve more or less the same thing without the std::tuple
, you can create a single-function variant of the above code:
#include <utility>
template<typename Function, typename... Args>
void va_for_each(Function&& fn, Args&&... args) {
using dummy = int[];
static_cast<void>(dummy {
0, (static_cast<void>(fn(std::forward<Args>(args))), 0)...
});
}
int main() {
auto action = [](auto&& arg) { arg.show(); };
va_for_each(action, w1, w2, w3, w4, w5, w6, t1, t2, t3);
}
The drawback of the second example is that it requires to specify the processing function first, therefore doesn't have the same look like the well known std::for_each
. Anyway with my compiler (GCC 5.4.0) using -O2
optimization level, they produce the same assembly output.
참고URL : https://stackoverflow.com/questions/34314193/iterating-over-different-types
'Program Tip' 카테고리의 다른 글
문장에있는 토큰의 word2vec에서 문장에 대한 벡터를 얻는 방법 (0) | 2020.11.26 |
---|---|
Swift XCTest UI에서 테스트 사이에 앱을 재설정하는 방법이 있습니까? (0) | 2020.11.26 |
값에 따라 DataGrid 셀 색상 변경 (0) | 2020.11.26 |
Rails 콘솔이 lib에서 모듈을 다시로드 할 수 있습니까? (0) | 2020.11.26 |
링크 위로 마우스를 가져갈 때 나타나는 손 모양 커서를 제거 할 수 있습니까? (0) | 2020.11.26 |