T.L*_*T.L 15 c++ templates metaprogramming c++17
我想根据类型将 a 移动或分配std::vector<Scalar>给a 。std::vector<float>Scalar
如果Scalar是float则移动,否则复制。
我试过这段代码
\n#include <vector>\n\nusing Scalar = double;\n\nint main()\n{\n std::vector<Scalar> x(10);\n std::vector<float> y(10);\n\n if constexpr(std::is_same<Scalar, float>::value)\n y = std::move(x); // line 11 (does not compile)\n else\n y.assign(x.begin(), x.end());\n\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n但我得到
\nmain.cpp:11:24: error: no match for \xe2\x80\x98operator=\xe2\x80\x99 (operand types are \xe2\x80\x98std::vector<float>\xe2\x80\x99 and \xe2\x80\x98std::remove_reference<std::vector<double>&>::type\xe2\x80\x99 {aka \xe2\x80\x98std::vector<double>\xe2\x80\x99})\n 11 | y = std::move(x);\n | ^\nRun Code Online (Sandbox Code Playgroud)\n我认为由于在编译时std::is_same<Scalar, float>::value评估为,那么下面的行将不会被编译。false
我使用编译它g++ -std=c++17 main.cpp -o exec。
如何根据类型移动x/y分配Scalar?
Tob*_*ght 15
因为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));
}
Run Code Online (Sandbox Code Playgroud)
我们可以对模板函数进行更好的约束(允许任何集合作为源),但这至少应该提供正确的出发方向。
T.L*_*T.L 10
正如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;
}
Run Code Online (Sandbox Code Playgroud)
小智 9
当is not时,赋值y = std::move(x);无效,因为is 的类型和is 的类型,并且它们不直接兼容。Scalarfloatystd::vector<float>xstd::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;
}
Run Code Online (Sandbox Code Playgroud)