使用检测习惯用法来确定类型是否具有具有特定签名的构造函数
Using the detection idiom to determine whether a type has a constructor with a specific signature
我正在考虑对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 上的测试代码(有点乱,我在手机上)
相关文章:
- 无论如何,我可以确定构造函数是否存在吗?
- 在对象构造期间,将指向尚未构造的子对象的指针传递给另一个子对象的构造函数是否危险?
- 构造函数是否有一种现代C++方法来了解其'container'类?
- 移动构造函数是否C++过时?
- 在 c++ 中将对象设置为等于同一类的构造函数是否有效?
- 具有默认值的单个参数构造函数是否与默认构造函数相同?
- 如何检测构造函数是否与抛出的析构函数无关
- 删除复制构造函数是否也会删除默认的复制/移动运算符?
- 构造函数是否unique_ptr初始化原始指针unique_ptr析构函数是否也删除关联的原始指针?
- 构造函数是否应该具有应用商店屏障?
- 将数据成员的指针传递给基类构造函数是否安全?
- 访问控制对于已删除的构造函数是否重要?
- 是否可以使用 EXPECT_CALL 来验证模拟对象的构造函数是否在某些时候调用成员函数?
- 让构造函数在其初始化列表中调用同一类的另一个构造函数是否有效
- 移动构造函数是否使shared_from_this无效
- 默认构造函数是否表示C 中的通用类型的零
- 没有参数的默认构造函数是否总是初始化变量?
- constexpr移动构造函数是否有意义
- 默认默认构造函数是否将变量初始化为零
- std::initializer_list私有构造函数是否从编译器那里得到非常特殊的处理