我们正在使用一个内部std::vector
作为输入的内部c ++库,但是我想编写应该能够接受std::vector
,std::set
或std::unordered_set
的包装函数当传递给该包装函数的输入是std::vector
本身时,我不想将其复制到临时向量中,因此有什么方法可以避免这种不必要的复制。
示例参考代码将更清楚地说明此问题:
#include <iostream>
#include <set>
#include <vector>
#include <unordered_set>
void print(const std::vector<int>& argVec)
{
for(auto elem:argVec)
{
std::cout<<elem<<std::endl;
}
}
template<template<typename...>class VecOrSet>
void wrapper(const VecOrSet<int>& input)
{
//How to avoid this temporary vector if input argument is vector itself
std::vector<int> temp(input.begin(),input.end());
print(temp);
}
int main()
{
std::vector<int> v{1,2,3};
std::set<int> s{4,5,6};
std::unordered_set<int> us{7,8,9};
wrapper(v);
wrapper(s);
wrapper(us);
return 0;
}
答案 0 :(得分:4)
您可以添加一个full specialization。
template<>
void wrapper(const std::vector<int>& input)
{
print(input);
}
或者只是添加另一个重载。
void wrapper(const std::vector<int>& input)
{
print(input);
}
或使用constexpr if(自C ++ 17起)。
template<template<typename...>class VecOrSet>
void wrapper(const VecOrSet<int>& input)
{
if constexpr (std::is_same_v<VecOrSet<int>, std::vector<int>>) {
print(input);
} else {
std::vector<int> temp(input.begin(),input.end());
print(temp);
}
}
答案 1 :(得分:1)
另一种解决方案可以是初始化temp
并通过另一个函数getIntVect()
(具有通用版本)
template <typename VoS>
std::vector<int> getIntVect (VoS const & input)
{ return { input.cbegin(), input.cend() }; }
将input
复制到std::vector<int>
中,并复制std::version<int>
的特定版本
std::vector<int> const & getIntVect (std::vector<int> const & input)
{ return input; }
返回对输入的const引用(即:避免复制)
因此,使用decltype(auto)
template<template<typename...>class VecOrSet>
void wrapper(const VecOrSet<int>& input)
{
decltype(auto) temp { getIntVect(input) };
print( temp );
}
temp
是对{{1}的引用,当input
为VecOrSet
时,否则为std::vector
的副本。
-编辑-
OP令人怀疑
我认为如果输入为vector,这行
input
将调用vector的副本构造函数
正如T.C.指出的那样,这对decltype(auto) temp{getIntVect(input)};
来说是正确的。 (谢谢!)。不适用于auto temp{getIntVect(input)};
尝试编译并运行以下代码
decltype(auto) temp{getIntVect(input)};
我从g ++和clang ++得到了这个输出
#include <iostream>
struct A
{
A ()
{ std::cout << "- default constructor" << std::endl; }
A (A const &)
{ std::cout << "- copy constructor" << std::endl; }
A (A &&)
{ std::cout << "- move constructor" << std::endl; }
};
template <typename T>
A foo (T const &)
{ return {}; }
A const & foo (A const & a)
{ return a; }
int main ()
{
std::cout << "--- 000" << std::endl;
A a0;
std::cout << "--- 001" << std::endl;
auto a1 { foo(a0) };
std::cout << "--- 002" << std::endl;
decltype(auto) a2 { foo(a0) };
std::cout << "--- 003" << std::endl;
decltype(auto) a3 { foo(0) };
std::cout << "--- 004" << std::endl;
}
如您所见,--- 000
- default constructor
--- 001
- copy constructor
--- 002
--- 003
- default constructor
--- 004
调用auto a1 { foo(a0) };
的副本构造函数(因为A
变成auto
,而A
导致返回值的副本A a1 { foo(a0) };
),但foo()
不调用构造函数(因为decltype(auto) a2 { foo(a0) };
变成decltype(auto)
,而A const &
只是将A const & a2 { foo(a0) };
链接到a2
(以foo(a0)
开头)。