c – 每当成员变量可以由可变参数构造时,有条件地启用构造函数

我有一个带有模板参数Tuple的类foo,我想提供一个可变参数构造函数来初始化类型为Tuple的成员变量m_elements,每当表达式m_elements {static_cast< typename Tuple :: value_type>(std :: forward< Elements>(元素))…}被定义.

我们可以通过以下方式执行此操作:

template<class Tuple>
struct foo
{
    using value_type = typename Tuple::value_type;

    template<class... Elements, class U = Tuple,
        class = decltype(U{ static_cast<value_type>(std::declval<Elements>())... })>
    foo(Elements&&... elements)
        : m_elements{ static_cast<value_type>(std::forward<Elements>(elements))... }
    {}

    Tuple m_elements;
};

现在,是否启用此构造函数还应取决于其他一些条件.所以,我需要写一些类似的东西

template<class... Elements, class U = Tuple,
    class = std::enable_if_t</* some other conditions depending on U */>,
    class = decltype(U{ static_cast<value_type>(std::declval<Elements>())... })>

我想用std :: is_constructible检查我的第一个条件,这样我就可以将这个检查移动到enable_if中.这可能吗?我试过使用std :: is_constructible_v< U,decltype(static_cast< value_type>(std :: declval< Elements>()))…>,但这似乎不等同于之前的检查.

例如,foo< bar< 3>> {1,2,3};同

template<std::size_t N>
struct bar
{
    using value_type = double;
    double data[N];
};

将使用上一个检查进行编译,但会产生新错误.

最佳答案 如
Rostislav所述,如果T不是函数类型,则std :: is_constructible_v< T,Args>如果变量定义为T obj(std :: declval< Args>()…);则为真;结构良好.条形码< 1>中的情况并非如此. obj(0.);,导致条< 1>没有相应的构造函数.

相反,bar1< 1> obj {0.};结构良好.使用建议的Detection Toolkit,我们可以使用

template<class T, typename... Arguments>
using initializable_t = decltype(T{ std::declval<Arguments>()... });

template<class T, typename... Arguments>
constexpr bool is_initializable_v = is_detected_v<initializable_t, T, Arguments...>;

并将支票更改为

template<class... Elements, class U = Tuple,
    class = std::enable_if_t<is_initializable_v<U, decltype(static_cast<value_type>(std::declval<Elements>()))...>>>

我认为这比普通的decltype方法更具可读性.

点赞