C ++ строгие правила псевдонимов и указатели на членов

Следующий код выдает предупреждение в G ++:

#include <iostream>
#include <cstdint>

template <typename T, typename P, typename Q>
Q T::*pointer_to(P T::*p, Q P::*q)
{
typedef Q T::* output_ptr;
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
size_t tmp = reinterpret_cast<const size_t&>(p) + reinterpret_cast<const size_t&>(q);
return reinterpret_cast<const output_ptr&>(tmp);
}

struct A { int x; };
struct B { A a; };

int main()
{
B b = B();
b.*pointer_to(&B::a, &A::x) = 1;
std::cout << b.a.x << std::endl;
}

В любом случае это работает правильно, но это заставляет меня беспокоиться.

Каково ваше мнение, подвержены ли эти указатели «подчиненных» более жестким вопросам псевдонимов, чем простые указатели членов?

4

Решение

Я бы рекомендовал не делать это таким образом.

Вы указали в своих комментариях, что вы пытались использовать вложенный std::bind, но есть проблема с версией компилятора, которую вы используете. Вместо того, чтобы прибегать к взлому, я бы бросил свой собственный повторный указатель на класс члена.

#include <iostream>
#include <cstdint>
#include <type_traits>
#include <utility>template<typename Ptr1, typename... Rest>
class pointer_to_sub;

template<typename ObjType, typename Class>
class pointer_to_sub<ObjType Class::* >
{
typedef ObjType Class::* ptr_type;

public:
typedef ObjType value_type;
typedef Class input_type;
pointer_to_sub(ptr_type input)  : ptr(input)
{

}

value_type& operator()(input_type& from) const
{
return from.*ptr;
}

value_type const& operator()(input_type const& from) const
{
return from.*ptr;
}

value_type& operator()(input_type* from) const
{
return from->*ptr;
}

value_type const& operator()(input_type const* from) const
{
return from->*ptr;
}private:

ptr_type ptr;
};template<typename ObjType, typename Class, typename... Rest >
class pointer_to_sub<ObjType Class::*, Rest...> : private pointer_to_sub<Rest...>
{
typedef ObjType Class::* ptr_type;
typedef pointer_to_sub<Rest...> base_type;
public:
typedef typename base_type::value_type value_type;
typedef Class input_type;

pointer_to_sub(ptr_type input, Rest... args) : base_type(args...), ptr(input)
{

}

value_type& operator()(input_type& from) const
{
return base_type::operator()(from.*ptr);
}

value_type const& operator()(input_type const& from) const
{
return base_type::operator()(from.*ptr);
}value_type& operator()(input_type* from) const
{
return base_type::operator()(from->*ptr);
}

value_type const& operator()(input_type const* from) const
{
return base_type::operator()(from->*ptr);
}
private:
ptr_type ptr;
};

template<typename T, typename... Args>
pointer_to_sub<T, Args...> make_pointer_to_sub(T t1, Args... args)
{
return pointer_to_sub<T, Args...>(t1, args...);
}

Вышесказанное в основном обеспечивает make_pointer_to_sub который принимает список указателей объектов-членов. Он принимает в качестве входных данных ссылку или указатель, который можно преобразовать в первый тип, а затем разыменовывает каждый из указателей по очереди. Это может быть улучшено, чтобы принять unique_ptr или же shared_ptr, но это на потом. Вы используете его, как показано ниже.

struct A { int x; double y;};
struct B { A a; };

int main()
{
auto ptr = make_pointer_to_sub(&B::a, &A::x);B b = B();
ptr(b) = 1;
// b.*pointer_to(&B::a, &A::x) = 1;

std::cout << b.a.x << std::endl;
ptr(&b) = 2;
std::cout << b.a.x << std::endl;

}

Если вам нужно, это может быть назначено std::function с соответствующими аргументами.

0

Другие решения


По вопросам рекламы [email protected]