编译时检查迭代器的父 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`");
}

DEMO

:

#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`");
}

DEMO 2

另一个潜在的 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 需求以及重载概念。您的函数声明也清楚地说明了它的要求,而不是将其延迟到静态断言。