如果我有使用 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 来保护构造函数。我可以将构造标记为显式,但我不想这样做。
您可以使用
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
来实现,虽然它通常有点丑陋(并且容易出错)并且会导致编译器的可读错误要少得多。
我喜欢
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/概念。