英文:
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();
// ...
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论