提问人:bradgonesurfing 提问时间:3/27/2023 更新时间:3/27/2023 访问量:71
如何在 c++17 中禁用过于通用的转发构造函数并延迟复制构造函数 [duplicate]
How to disable overly generic forwarding constructor in c++17 and defer to copy constructor [duplicate]
问:
如果我使用 c++20 概念编写简单类
#include <array>
#include <type_traits>
template <class T, int N>
struct MyVec {
std::array<T, N> m_vec;
template <typename... Q>
MyVec(Q&&... args)
requires (std::is_same_v<Q,T> && ...):
m_vec{std::forward<Q>(args)...} {}
};
以及它被使用的例子
int main(int argc, char* argv[]) {
using V = MyVec<double, 2>;
V v0(1., 2.);
V v1(1., 2.);
V v2 = v0;
}
requires 语句可防止复制构造函数被过于泛型的转发构造函数隐藏。查看 https://godbolt.org/z/8Me19v7Ks
如果删除 requires 语句,则该行将无法编译。V v2 = v0
但是,我不能使用概念,因为这需要在仅限 c++17 的上下文中。我被困在试图弄清楚如何使用enable_if来保护构造函数。我可以将构造标记为显式,但我宁愿不这样做。
答:
4赞
Holt
3/27/2023
#1
您可以使用禁用模板:enable_if
template <class T, int N>
struct MyVec {
std::array<T, N> m_vec;
template <typename... Q,
std::enable_if_t<(std::is_convertible_v<Q, T> && ...), int> = 0>
MyVec(Q&&... args)
: m_vec{std::forward<Q>(args)...} {}
};
我不是概念方面的专家,但大多数(全部?)你可以用或类似的东西来实现,尽管它通常有点丑陋(而且容易出错),并且会导致编译器的可读性大大降低。requires
enable_if
评论
0赞
bradgonesurfing
3/27/2023
那行得通。godbolt.org/z/5K438vEdM在过去的 6 个月里,我一直在使用概念,以至于忘记了如何做旧 skool。
1赞
Jarod42
3/27/2023
#2
我喜欢包装器的另一种选择是:std::array
template <typename T, std::size_t>
using always_t = T;
template <class T, class Seq>
struct MyVecImpl;
template <class T, std::size_t... Is>
struct MyVecImpl<T, std::index_sequence<Is...>>
{
std::array<T, sizeof...(Is)> m_vec;
MyVecImpl(always_t<T, Is>... ts) : m_vec{std::move(ts)...}{}
};
template <class T, int N>
using MyVec = MyVecImpl<T, std::make_index_sequence<N>>;
不需要 SFINAE/concepts。
评论
0赞
bradgonesurfing
3/27/2023
这很有趣。为什么这样做?其中,这如何在 ts 上生成参数包。例如,这不起作用,godbolt.org/z/6j967n4Tj 我一直认为要生成参数包,需要在实际方法上有一个模板。
1赞
Holt
3/27/2023
@bradgonesurfing 不是参数包,因此不能使用 while is,因此可以使用 和 。请注意,在这种情况下,如果您想实现您已经拥有的内容,您将需要 和 版本,因为您不能将完美转发与 一起使用。T
T...
Is
Is...
always_t<T, Is>...
&&
const&
always_t<T, Is>...
评论
sizeof...(Q) == N
using V = std::array<double, 2>
main