编译时检查迭代器的父 class public 成员是否存在
Compile-time check if iterator's parent class public member exists
我有一个 class:
class A
{
// ...
public:
std::string s;
// ...
}
还有一个函数:
void some_process(RandomIt first, RandomIt last)
{
static_assert(/* some check if *RandomIt has member with name `s` */,
"Iterator must point to an object with member `s`");
// further process using RandomIt and using *RandomIt.s
}
如何在 C++ 至 C++17 中实现此检查?
#include <type_traits>
#include <utility>
template <typename T, typename = void>
struct has_s : std::false_type {};
template <typename T>
struct has_s<T, decltype(void(std::declval<T>()->s))> : std::true_type {};
template <typename RandomIt>
void some_process(RandomIt first, RandomIt last)
{
static_assert(has_s<RandomIt>{},
"Iterator must point to an object with member `s`");
}
#include <type_traits>
#include <utility>
template <typename T>
using has_s_t = decltype(std::declval<T>()->s);
template <typename RandomIt>
void some_process(RandomIt first, RandomIt last)
{
static_assert(std::is_detected_v<has_s_t, RandomIt>,
"Iterator must point to an object with member `s`");
}
另一个潜在的 C++1z 选项是概念。这是一个概念的简单示例,它本身可能没有用,但可以根据您的情况使用该想法来制作您需要的东西。
template<typename T>
concept bool PointeeHasSMember = requires(T t)
{
t->s; // require t->s to be a valid expression
};
struct with_s
{
int s;
};
struct no_s {};
void some_process(PointeeHasSMember first, PointeeHasSMember last) {}
int main()
{
with_s* with;
no_s* without;
some_process(with, with); // compiles
some_process(without, without); // doesn't compile
}
在 latest GCC 下,第二次调用在相关行 concept 'PointeeHasSMember<no_s*>' was not satisfied' was not satisfied
.
中产生错误
使用概念的优点是实现简单,甚至与检测习语相比也是如此,而且概念成为函数模板的一部分。您可以灵活地嵌套需求、执行 on-the-fly 需求以及重载概念。您的函数声明也清楚地说明了它的要求,而不是将其延迟到静态断言。
我有一个 class:
class A
{
// ...
public:
std::string s;
// ...
}
还有一个函数:
void some_process(RandomIt first, RandomIt last)
{
static_assert(/* some check if *RandomIt has member with name `s` */,
"Iterator must point to an object with member `s`");
// further process using RandomIt and using *RandomIt.s
}
如何在 C++ 至 C++17 中实现此检查?
#include <type_traits>
#include <utility>
template <typename T, typename = void>
struct has_s : std::false_type {};
template <typename T>
struct has_s<T, decltype(void(std::declval<T>()->s))> : std::true_type {};
template <typename RandomIt>
void some_process(RandomIt first, RandomIt last)
{
static_assert(has_s<RandomIt>{},
"Iterator must point to an object with member `s`");
}
#include <type_traits>
#include <utility>
template <typename T>
using has_s_t = decltype(std::declval<T>()->s);
template <typename RandomIt>
void some_process(RandomIt first, RandomIt last)
{
static_assert(std::is_detected_v<has_s_t, RandomIt>,
"Iterator must point to an object with member `s`");
}
另一个潜在的 C++1z 选项是概念。这是一个概念的简单示例,它本身可能没有用,但可以根据您的情况使用该想法来制作您需要的东西。
template<typename T>
concept bool PointeeHasSMember = requires(T t)
{
t->s; // require t->s to be a valid expression
};
struct with_s
{
int s;
};
struct no_s {};
void some_process(PointeeHasSMember first, PointeeHasSMember last) {}
int main()
{
with_s* with;
no_s* without;
some_process(with, with); // compiles
some_process(without, without); // doesn't compile
}
在 latest GCC 下,第二次调用在相关行 concept 'PointeeHasSMember<no_s*>' was not satisfied' was not satisfied
.
使用概念的优点是实现简单,甚至与检测习语相比也是如此,而且概念成为函数模板的一部分。您可以灵活地嵌套需求、执行 on-the-fly 需求以及重载概念。您的函数声明也清楚地说明了它的要求,而不是将其延迟到静态断言。