如果模板模板参数是矢量,则需要不同的行为
Different behavior needed if template template parameter is vector
我们正在使用一个内部 c++ 库,它将std::vector
作为输入,但是我想编写应该能够接受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;
}
您可以添加完整的专业化。
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);
}
}
另一种解决方案可能是temp
通过另一个函数进行初始化:getIntVect()
,具有通用版本
template <typename VoS>
std::vector<int> getIntVect (VoS const & input)
{ return { input.cbegin(), input.cend() }; }
复制std::vector<int>
中的input
,以及std::version<int>
的特定版本
std::vector<int> const & getIntVect (std::vector<int> const & input)
{ return input; }
返回对输入的常量引用(即:避免复制)
因此,使用decltype(auto)
,
template<template<typename...>class VecOrSet>
void wrapper(const VecOrSet<int>& input)
{
decltype(auto) temp { getIntVect(input) };
print( temp );
}
temp
是对input
的引用,当VecOrSet
std::vector
时,或者input
的副本,否则。
--编辑--
OP 是可疑的
我认为如果输入是矢量,这一行
decltype(auto) temp{getIntVect(input)};
将调用矢量的复制构造函数
正如T.C.所指出的,auto temp{getIntVect(input)};
也是如此(谢谢!不适合decltype(auto) temp{getIntVect(input)};
尝试编译并运行以下代码
#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;
}
我得到(来自 g++ 和 clang++)这个输出
--- 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)
(因此a0
)。
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 如果返回 -1,时间() 的参数是否被修改?
- 如果模板没有可变参数,则 Lambda 被推导出为 std::function
- 如果需要转换,我可以在读取参数的同时将其移动到另一个参数吗?
- 如果模板参数是另一个模板的实例化,则键入特征测试
- 如果可推导类型上有替换,可变参数模板类型推导会使编译器崩溃
- C++如果两个模板函数都与参数列表匹配,将调用哪个模板
- 如果参数与数据成员的参数同名,该怎么办?
- 如果条件,当我想第二个参数时
- Qt5:连接:如果插槽的参数少于信号,如何使用"连接"
- 在 c++ 中,如果我创建一个接受一个具有默认值的参数的构造函数 - 它会用作默认(空)构造函数吗?
- 是否可以将带有捕获和参数的 lambda 传递给另一个函数?如果是这样,如何?
- 如果您为类的一个对象动态分配内存作为参数,会发生什么
- 使用 std::move 将参数传递给函数,如果该参数声明为按值传递或使用移动操作数 &&,是否有区别?
- 如果模板模板参数是矢量,则需要不同的行为
- C++14 及更高版本是否允许 Lambda 函数的默认参数?如果是这样,怎么办?
- 何时在 c++ 中使用参数(如果有的话)?
- 函数还是函子作为模板参数?(如果不需要状态)
- 提升:取消引用模板参数(如果它是指针)
- make_heap() 函数参数 - 如果我不想包含某些元素怎么办?