编译时检查迭代器的父类公共成员是否存在

时间:2016-01-04 22:02:23

标签: templates c++11 c++14 typetraits c++17

我有一个班级:

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 ++ 17到C ++实现此检查?

2 个答案:

答案 0 :(得分:4)

+-----+---------------+---------------+
| id  |    team_A     |    team_B     |
+-----+---------------+---------------+
|  1  |   Barcelona   |  Real Madrid  |
+-----+---------------+---------------+
|  2  |     Milan     |     Inter     |
+-----+---------------+---------------+

DEMO

#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 2

答案 1 :(得分:2)

另一个潜在的C ++ 1z选项是Concepts。这是一个概念的简单示例,它本身可能没有用,但这个想法可以用来制作你所需要的东西。

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的错误。

使用概念的优点是简单的实现,甚至与检测习语相比,并且概念成为功能模板的一部分。您可以灵活地嵌套需求,执行动态要求以及对概念进行重载。您的函数声明也明确说明了它的要求,而不是将其延迟到静态断言。