伙计们。我试图将指向从公共基类派生的类的指针向量作为函数参数传递。问题是,我希望在一行中完成它,而不是先声明向量,然后通过引用函数传递它。我提出了以下解决方案,它使用包装类来封装每个向量元素,并通过显式转换运算符将相应的指针传递给向量构造函数。
我不确定这种方法的后果,特别是在向量构造和/或函数调用期间,类是否在任何时候被复制多次。你们能给我反馈或者更好的解决方案吗?谢谢。
class Base
{
public:
};
class Derived1 : public Base
{
public:
Derived1(int number){}
};
class Derived2 : public Base
{
public:
Derived2(const char* string){}
};
template <typename T> class Wrapper
{
private:
T element;
public:
Wrapper<T>(int number):element(number){}
Wrapper<T>(const char* string):element(string){}
operator T* (){return &element;}
};
void Foo(const std::vector<Base*>& list)
{
//DO SOMETHING
}
int main()
{
Foo(std::vector<Base*>({Wrapper<Derived1>(1), Wrapper<Derived2>("name")});
return 0;
}
是的,这是实现目标的合理方法(尽管这个目标可能一开始就不值得实现)。
正如“一些程序员花花公子”评论的那样,由于
Foo
被声明为采用 std::vector<Base*>
,所以 应该 可以只传递该向量的支撑元素,而不在调用者一侧重复类型 std::vector<Base*>
。 (但如果 Foo
有其他重载,或者是模板,那么这不一定有效。)此外,main
默认返回 0
。因此:
int main() {
Foo({Wrapper<Derived1>(1), Wrapper<Derived2>("name")});
}
你的
Wrapper
可以完美地将它的参数转发给T
的构造函数;查看 std::make_unique<Derived1>(1)
看看这是如何完成的。另外,我个人会将其 API 设为带有动词名称的函数,而不是带有名词名称的类。 神箭:
template<class T, class... Args>
auto wrap(Args&&... args) {
struct Wrapper {
T elt_;
operator T*() { return &elt_; }
};
return Wrapper{ T(std::forward<Args>(args)...) };
}
int main() {
Foo({wrap<Derived1>(1), wrap<Derived2>("abc")});
}
我观察到(偶然:))如果你忘记让
Derived1
派生自 Base
,错误消息将变得 crazy 神秘——因为你要求从花括号初始化列表创建一个向量其中的每个元素都隐式转换为其他元素。这是很多层的“隐含性”。
一种可能更简单但效率较低的方法是执行类似的操作(Godbolt),制作一个包含存储在其他地方的元素地址的全新向量:
template<class... Ptrs>
std::vector<Base*> vector_of_ptrs(Ptrs&&... args) {
return {args.get()...};
}
int main() {
Foo(vector_of_ptrs(
std::make_unique<Derived1>(1),
std::make_unique<Derived2>("abc")
));
}
或者为了获得更好的错误消息,通过 folding over
push_back
插入向量的元素:
template<class... Ptrs>
std::vector<Base*> vector_of_ptrs(Ptrs&&... args) {
std::vector<Base*> r;
(r.push_back(args.get()) , ...);
return r;
}
我希望在一行中完成它,而不先声明向量
std::vector
有一个初始化列表构造函数,所以你可以省略std::vector
并只提供支撑初始化列表,如下所示:
//--v------------------------------------------>no need to explicitly specify std::vector<Base*>
Foo({Wrapper<Derived1>(1), Wrapper<Derived2>("name")});