提问人:T.L 提问时间:8/7/2023 最后编辑:Peter MortensenT.L 更新时间:8/10/2023 访问量:894
如何使用 if constexpr 根据它们的类型将一个向量移动或分配给另一个向量?
How can I move or assign one vector into another depending of their type using if constexpr?
问:
我想根据类型将 a 移动或分配给 a .std::vector<Scalar>
std::vector<float>
Scalar
如果是然后移动,否则复制。Scalar
float
我试过这个代码
#include <vector>
using Scalar = double;
int main()
{
std::vector<Scalar> x(10);
std::vector<float> y(10);
if constexpr(std::is_same<Scalar, float>::value)
y = std::move(x); // line 11 (does not compile)
else
y.assign(x.begin(), x.end());
return 0;
}
但我明白了
main.cpp:11:24: error: no match for ‘operator=’ (operand types are ‘std::vector<float>’ and ‘std::remove_reference<std::vector<double>&>::type’ {aka ‘std::vector<double>’})
11 | y = std::move(x);
| ^
我认为既然是在编译时计算的,那么下面的行就不会被编译。std::is_same<Scalar, float>::value
false
我使用 .g++ -std=c++17 main.cpp -o exec
如何根据类型移动/分配到?x
y
Scalar
答:
10赞
T.L
8/7/2023
#1
正如 HolyBlackCat 在评论中指出的那样,正如 cppref 中所述:“在模板之外,完全检查丢弃的语句。(https://en.cppreference.com/w/cpp/language/if)。
这是一个涉及一个新模板函数的潜在解决方案
#include <vector>
template <typename U, typename V>
void move_or_copy(std::vector<U>& y, std::vector<V>&& x) {
if constexpr(std::is_same<U,V>::value) {
y = std::move(x);
} else {
y.assign(x.begin(), y.end());
}
}
using Scalar = double;
int main()
{
std::vector<Scalar> x(10);
std::vector<float> y(10);
move_or_copy(y, x);
return 0;
}
9赞
Turan-Yahya Gazizuly
8/7/2023
#2
赋值在 不是 时无效,因为 是 类型 和 是 类型 ,并且它们不直接兼容。y = std::move(x);
Scalar
float
y
std::vector<float>
x
std::vector<Scalar>
#include <vector>
#include <type_traits>
using Scalar = double;
template <typename T, typename A>
void moveOrAssign(std::vector<T>& dest, std::vector<A>&& source) {
if constexpr(std::is_same_v<T, A>) {
dest = std::move(source);
} else {
dest.assign(source.begin(), source.end());
}
}
int main() {
std::vector<Scalar> x(10);
std::vector<float> y(10);
moveOrAssign(y, std::move(x));
return 0;
}
评论
0赞
Jan Schultke
8/7/2023
我认为这个解决方案比另一个更优雅,因为它不需要过载分辨率,而且整体上更简短、更直观。
1赞
pptaszni
8/7/2023
但是这个代码是错误的,或者我不知道如何复制粘贴?godbolt.org/z/9xrhvP176两个向量都使用相同的模板参数,并且与 冲突。T
float
double
0赞
Turan-Yahya Gazizuly
8/7/2023
您可以添加新的并使用它!typename
1赞
chrysante
8/7/2023
如果您编辑了错误,这将是一个很好的解决方案
2赞
François Andrieux
8/7/2023
由于是右值引用,因此第二种情况可以通过使用 std::make_move_iterator
来改进,以避免在可能重要的情况下复制元素。例如,当前实现可能会在 a 的情况下制作冗余副本,而在 .source
moveOrAssign
std::vector<std::string>
std::vector<std::unique_ptr<...>>
15赞
Toby Speight
8/7/2023
#3
因为不是模板,所以两端都必须有效。要使用这种方式,它需要位于模板中。main()
if constexpr
if constexpr
值得庆幸的是,一个好的模板使这个逻辑更容易重用:
#include <vector>
template<typename T, typename U>
void move_or_copy(std::vector<T>& dest, std::vector<U>&& src)
{
if constexpr(std::is_same_v<T,U>)
dest = std::move(src);
else
dest.assign(src.begin(), src.end());
}
using Scalar = double;
int main()
{
std::vector<Scalar> x(10);
std::vector<float> y(10);
move_or_copy(y, std::move(x));
}
我们可以更好地约束模板函数(允许任何集合作为源),但这至少应该提供正确的方向。
评论
2赞
pptaszni
8/7/2023
是的,将集合作为模板参数,第二个参数将是真正的转发参考。目前,例如 是不可能的。template <typename Container1, typename Container2>
move_or_copy(y, y);
评论
if constexpr
只有当条件取决于模板参数时,模板内部才会有魔力。if