Kar*_*yan 2 c++ templates language-lawyer c++17
我正在玩下面的代码。
#include <iostream>
#include <span>
#include <vector>
std::vector v{1,2,3,4,5,6};
template <template <typename, std::size_t> class S>
S<int, std::dynamic_extent> GetSpan()
{
return v;
}
int main()
{
auto x = GetSpan<std::span>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
GCC 和 Clang 都接受了这一点。但是,如果我std::vector
在函数中设置 local in GetSpan()
,则 i. e
template <template <typename, std::size_t> class S>
S<int, std::dynamic_extent> GetSpan()
{
std::vector v{1,2,3,4,5,6};
return v;
}
Run Code Online (Sandbox Code Playgroud)
Clang 仍然接受该代码,但 gcc 拒绝它。哪个编译器就在这里,为什么?
您的代码无法在 C++23 模式下编译。这是因为返回变量时进行了简化的隐式移动。(参见:cpppreference、P2266R3)
std::vector v{1,2,3,4,5,6};
return v;
Run Code Online (Sandbox Code Playgroud)
是相同的
std::vector v{1,2,3,4,5,6};
return std::move(v);
Run Code Online (Sandbox Code Playgroud)
...并且 astd::span<int>
不能从右值向量构造。
之前的行为是尝试移动,如果该移动不可能,它就会复制。
看起来 gcc 即使在 C++20 模式下也会进行简化的移动。
其中之一可以修复它:
return (std::vector<int>&) v;
return static_cast<std::vector<int>&>(v); // (This seems like the recommended solution)
return static_cast<decltype((v))>(v);
return static_cast<decltype(v)&>(v);
return std::identity{}(v);
// These two may have slightly different behaviour depending on
// the constructors of the return type, but work here
return { v };
return S<int, std::dynamic_extent>(v);
Run Code Online (Sandbox Code Playgroud)