如何要求C++模板参数具有具有给定签名的某些方法
How to require a C++ template parameter to have some methods with a given signature?
我想定义一个类,它有一个模板参数T
。我想确保T
有一个void Update(uint32_t)
和一个int32_t GetResult() const
的方法。我知道当我尝试调用这些方法之一时,用户会收到错误,但我想确保(可能使用静态断言(它们尽快存在。
我只能找到解决方案来检查类T
是否派生自其他类U
,但这不是我想要的。我想允许任何具有上述方法的类。
你不需要这方面的概念,尽管这些概念会有所帮助。这段代码将在 C++11 中愉快地工作。
#include <type_traits>
#include <cstdint>
using namespace std;
struct A {
void Update(uint32_t);
int32_t GetResult() const;
};
struct B {
};
using namespace std;
template <typename T, typename = typename enable_if<
is_same<decltype(&T::Update), void (T::*)(uint32_t)>::value &&
is_same<decltype(&T::GetResult), int32_t (T::*)() const>::value
>::type>
struct CLS
{
};
using namespace std;
int main() {
CLS<A> a; // works
CLS<B> b; // fails to compile
return 0;
}
请注意,此代码检查确切的函数签名,因此Update(int)
不会传递。
编辑:添加了常量以获取结果
对于 C++20 中引入的概念,这对于 require 表达式和 require 子句来说是微不足道的。在代码中,关键字 requires
出现两次。第一个引入了 require 子句,第二个引入了 require 表达式。
template <typename T>
requires requires (T& a, const T& b, uint32_t i) {
a.Update(i);
{b.GetResult()} -> int32_t;
}
void foo(T& x)
{
// ...
}
(现场测试(
在 C++20 之前,您可以编写一个部署 SFINAE 的 trait 类:
template <typename T>
class foo_traits {
static auto check(...) -> std::false_type;
template <typename U>
static auto check(U x) -> decltype((void)x.Update(uint32_t{}), std::true_type{});
public:
static constexpr bool has_update = decltype(check(std::declval<T>()))::value;
};
现在你可以像这样使用它:
template <typename T>
void foo(T& x)
{
static_assert(foo_traits<T>::has_update, "blah blah blah");
}
或:
template <typename T>
std::enable_if_t<foo_traits<T>::has_update> foo(T& x)
{
}
(现场测试(
GetResult
可以类似地处理。
注意:上面的代码只确保表达式有效,而不是确保精确的签名。当然,你也可以这样做。以下是概念的方法:
template <typename T>
requires requires (T& a, const T& b, uint32_t i) {
a.Update(i);
{&T::GetResult} -> std::int32_t (T::*)() const;
}
void foo(T& x)
{
// ...
}
Radosław Cybulski的回答已经展示了如何在没有概念的情况下做到这一点,所以我不再展示它。
如果你想使用一个static_assert
,这是可能的:
static_assert(static_cast< void (T::*)(uint32_t) >(&T::update),
"Need void T::update(uint32_t");
强制转换检查是否可以解决重载问题,即是否存在正确的签名。
相关文章:
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 没有为自己的结构调用列表推回方法
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在类定义之后定义一个私有方法
- 枚举环境变量的惯用C++14/C++17方法
- 初始化具有非默认构造函数的std::数组项的更好方法