使用检测习惯用法来确定类型是否具有具有特定签名的构造函数

Using the detection idiom to determine whether a type has a constructor with a specific signature

本文关键字:构造函数 是否 类型 检测 习惯 惯用法      更新时间:2023-10-16

我正在考虑对C++检测习惯用法的标准库支持的建议。它是一个类似特征的元函数,用于确定类型T是否具有名为 T::type 的类型成员或具有特定签名的成员函数,例如:

#include <iostream>

template<class...>
using void_t = void;
template<class, template<class> class, class = void_t<>>
struct detect : std::false_type { };
template<class T, template<class> class Operation>
struct detect<T, Operation, void_t<Operation<T>>> : std::true_type { };

template<class T>
using bar_t = decltype(std::declval<T>().bar());
template<class T>
using bar_int_t = decltype(std::declval<T>().bar(0));
template<class T>
using bar_string_t = decltype(std::declval<T>().bar(""));

struct foo
{
    int bar() { return 0; }
    int bar(int) { return 0; }
};

int main()
{
    std::cout << detect<foo, bar_t>{} << std::endl;
    std::cout << detect<foo, bar_int_t>{} << std::endl;
    std::cout << detect<foo, bar_string_t>{} << std::endl;
    return 0;
}

上面的代码产生预期的输出

1
1
0

您可以进行现场演示。现在,我想测试一个类型T是否具有具有特定签名的构造函数,例如 T::T(U)另一种类型的U。是否可以使用检测习惯用语来做到这一点?

修改detect类以允许可变参数:

template <typename...>
using void_t = void;
template <typename AlwaysVoid, template <typename...> class Operation, typename... Args>
struct detect_impl : std::false_type { };
template <template <typename...> class Operation, typename... Args>
struct detect_impl<void_t<Operation<Args...>>, Operation, Args...> : std::true_type { };

添加对空类型进行硬编码的别名:

template <template <typename...> class Operation, typename... Args>
using detect = detect_impl<void, Operation, Args...>;
//                         ~~~^

编写检测器:

template <typename T, typename... Us>
using has_constructor = decltype(T(std::declval<Us>()...));

测试您的课程:

static_assert(detect<has_constructor, foo, foo>{}, "!");

演示

更好的是:std::is_constructible


template<class U>
struct constructable_from {
  template<class T>
  using test_t = decltype(T(std::declval<U>()));
};
// usage
detect<foo, constructable_from<baz>::test_t> {}

这似乎适用于您的代码。可以轻松扩展它以支持使用可变参数模板的多参数构造函数。我不知道这是否是"使用检测成语",但这是我前段时间一直在使用的。

我在 ideone 上的测试代码(有点乱,我在手机上)