英文:
Base class initializer list in for loop
问题
有没有更好/更清晰的方法来做到这一点?
class Base {};
class Derived1 : Base {};
class Derived2 : Base {};
//================================
Derived1 var1, var2;
Derived2 var3, var4;
for (auto& var : {var1, var2, var3, var4}) {
...
}
英文:
Anyone have a better/cleaner way to do this?
class Base {};
class Derived1 : Base {};
class Derived2 : Base {};
//================================
Derived1 var1, var2;
Derived2 var3, var4;
for (auto* var : std::initializer_list<Base*>{&var1, &var2, &var3, &var4}) {
...
}
Would like to avoid having to explicitly type the initializer_list
and, for bonus points, using references and not having to resort to pointers.
答案1
得分: 3
唯一的替代方式,但这可能不是您要找的方式:
class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
Derived1 var1, var2;
Derived2 var3, var4;
Base* objects[] = { &var1, &var2, &var3, &var4 };
for (auto* var : objects) {
...
}
英文:
The only alternate way, but it's probably not what you are looking for:
class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
Derived1 var1, var2;
Derived2 var3, var4;
Base* objects[] = { &var1, &var2, &var3, &var4 };
for (auto* var : objects) {
...
}
答案2
得分: 1
你无法自动推断Base
。而且,甚至没有将Derived1*
或Derived2*
隐式转换为Base*
,因为你使用了一个私有基类。
我假设你实际上想要在以下代码中使用公共基类
class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
你无法推断出Derived1
和Derived2
的公共基类,因此如果要使用任何可迭代的内容,你需要手动指定类型。
但是,你可以创建一个模板函数,带有参数包,以执行每个传递参数的函数器,或者创建一个可迭代对象,在解引用迭代器时返回对Base
的引用。
在以下代码中,我展示了这两种选项,但为了简单起见,我使用了std::array
,其中包含std::reference_wrapper<Base>
,而不是实现自定义集合,该集合具有返回对Base
的引用的迭代器。
template<class F, class... Args>
void ForEach(F&& f, Args&&... args)
{
((f(std::forward<Args>(args))), ...);
}
void printType(Derived1 const&)
{
std::cout << "Derived1\n";
}
void printType(Derived2 const&)
{
std::cout << "Derived2\n";
}
void printType(Base const&)
{
std::cout << "Base\n";
}
template<class T, class ...Args>
std::array<std::reference_wrapper<T>, sizeof...(Args)> AsIterable(Args& ...args)
{
return {args...};
}
int main()
{
Derived1 var1, var2;
Derived2 var3, var4;
std::cout << "generic lambda:\n";
ForEach([](auto& x)
{
printType(x);
}, var1, var2, var3, var4);
std::cout << "lambda with typed parameter:\n";
ForEach([](Base& x)
{
printType(x);
}, var1, var2, var3, var4);
std::cout << "range-based for loop with reference wrapper array:\n";
for (auto& var : AsIterable<Base>(var1, var2, var3, var4))
{
// 注意:var的类型是std::reference_wrapper<Base>&,而不是上面提到的Base&
printType(var);
}
std::cout << "pointer values(main):\n"
<< &var1 << '\n'
<< &var2 << '\n'
<< &var3 << '\n'
<< &var4 << '\n'
;
std::cout << "pointer values(lambda):\n";
ForEach([](Base& x)
{
std::cout << &x << '\n';
}, var1, var2, var3, var4);
std::cout << "pointer values(range-based for):\n";
for (auto& var : AsIterable<Base>(var1, var2, var3, var4))
{
std::cout << &var.get() << '\n';
}
}
英文:
You cannot automatically deduce Base
. Furthermore there isn't even an implicit conversion of Derived1*
or Derived2*
to Base*
, since you're using a private base class.
I'm assuming you actually wanted public base classes in the following code
class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
.
You cannot deduce the common base class of both Derived1
and Derived2
, so the type actually needs to be mentioned, if you want to use anything that's iterable, you need to manually specify the type.
However you could create a template function with a parameter pack to either execute a functor for every parameter passed or to create something that is an iterable that returns references to Base
when dereferencing the iterator.
In the following I show both options, but for simplicity's sake I go with an std::array
of std::reference_wrapper<Base>
instead of implementing custom collection that has an iterator returning references to Base
.
template<class F, class...Args>
void ForEach(F&& f, Args&&...args)
{
((f(std::forward<Args>(args))), ...);
}
void printType(Derived1 const&)
{
std::cout << "Derived1\n";
}
void printType(Derived2 const&)
{
std::cout << "Derived2\n";
}
void printType(Base const&)
{
std::cout << "Base\n";
}
template<class T, class ...Args>
std::array<std::reference_wrapper<T>, sizeof...(Args)> AsIterable(Args& ...args)
{
return {args...};
}
int main()
{
Derived1 var1, var2;
Derived2 var3, var4;
std::cout << "generic lambda:\n";
ForEach([](auto& x)
{
printType(x);
}, var1, var2, var3, var4);
std::cout << "lambda with typed parameter:\n";
ForEach([](Base& x)
{
printType(x);
}, var1, var2, var3, var4);
std::cout << "range-based for loop with reference wrapper array:\n";
for (auto& var : AsIterable<Base>(var1, var2, var3, var4))
{
// note: var has type std::reference_wrapper<Base>&, not Base& as mentioned above
printType(var);
}
std::cout << "pointer values(main):\n"
<< &var1 << '\n'
<< &var2 << '\n'
<< &var3 << '\n'
<< &var4 << '\n'
;
std::cout << "pointer values(lambda):\n";
ForEach([](Base& x)
{
std::cout << &x << '\n';
}, var1, var2, var3, var4);
std::cout << "pointer values(range-based for):\n";
for (auto& var : AsIterable<Base>(var1, var2, var3, var4))
{
std::cout << &var.get() << '\n';
}
}
答案3
得分: 0
如果您更喜欢使用引用而不是指针(正如您在问题中明确指定的),您可以使用 std::reference_wrapper
。
在下面的示例中,我还使用了 std::array
作为容器,而不是原始的 C 数组:
#include <functional>
#include <array>
class Base { };
class Derived1 : public Base { };
class Derived2 : public Base { };
int main()
{
Derived1 var1, var2;
Derived2 var3, var4;
std::array<std::reference_wrapper<Base>, 4> var_refs = { var1, var2, var3, var4 };
for (auto & var_ref : var_refs)
{
Base& var = var_ref.get();
// ...
}
}
英文:
If you prefer to use references over pointers (as you specified explicitly in your question),
you can use std::reference_wrapper
.
In the example below I also used std::array
instead of a raw C array as a container:
#include <functional>
#include <array>
class Base { };
class Derived1 : public Base { };
class Derived2 : public Base { };
int main()
{
Derived1 var1, var2;
Derived2 var3, var4;
std::array<std::reference_wrapper<Base>, 4> var_refs = { var1, var2, var3, var4 };
for (auto & var_ref : var_refs)
{
Base& var = var_ref.get();
// ...
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论