4

次のコードは、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

1 に答える 1

0

このようにしないことをお勧めします。

ネストされた を使用しようとしたことをコメントで述べましたが、使用し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、適切な引数を使用してこれを に割り当てることができます。

于 2014-06-06T12:46:10.847 に答える