如何在 C++17 中禁用过于通用的转发构造函数并推迟到复制构造函数

问题描述 投票:0回答:2

如果我有使用 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 来保护构造函数。我可以将构造标记为显式,但我不想这样做。

c++ c++17 copy-constructor perfect-forwarding stdarray
2个回答
4
投票

您可以使用

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
投票

我喜欢

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/概念。

© www.soinside.com 2019 - 2024. All rights reserved.