##やりたいこと
例
get_index(&Point::y); // 1
get_index(&Point::z); // 2
こういう感じに「メンバ変数ポインタ→それが何番目の構造体の要素か」をしりたい
実装方法
構造化束縛で取り出した変数の参照のポインタと変数ポインタを比較していくことで取得することができる
実装例
get_index.hpp
#include <cassert>
template<class T,class R>
std::size_t get_index3(R T::*p){
T t;
auto &[e0,e1,e2] = t;
int idx=0;
for(auto tp:{&e0,&e1,&e2}){
if(tp == &(t.*p))
return idx;
idx+=1;
}
return 42;
}
main.cpp
struct Point{
int x;
int y;
int z;
};
int main()
{
std::size_t x = get_index3(&Point::x);
std::size_t y = get_index3(&Point::y);
std::size_t z = get_index3(&Point::z);
assert(x==0);
assert(y==1);
assert(z==2);
}
やったー
コンパイル時
型の時間の話
コンパイル時に処理する場合、上の実装だと
任意の構造体のコンストラクタ呼び出しは定数式ではない可能性が高いため T t
の部分が問題になる
そのため、コンストラクタの呼び出しは実行時までしないことにする
コンストラクタの呼び出しをしないと変数の値は未定義になるのでダメそうだが、変数のアドレスには影響を及ぼさないため定数式にすることができる1
実装例
get_index.hpp
#include <iostream>
template<class T>
class Class{
static inline T t{};
public:
template<auto p>
static constexpr std::size_t get(){
auto &[e0,e1,e2] = t;
int idx=0;
for(auto tp:{&e0,&e1,&e2}){
if(tp == &(t.*p))
return idx;
idx+=1;
}
return 42;
}
};
main.cpp
struct S{
std::string x;
std::string y;
std::string z;
};
int main()
{
constexpr auto x = Class<S>::get<&S::x>();
constexpr auto y = Class<S>::get<&S::y>();
constexpr auto z = Class<S>::get<&S::z>();
static_assert(x==0);
static_assert(y==1);
static_assert(z==2);
}
gcc 7.3 : https://wandbox.org/permlink/pJTCcz9mDKesTDdJ
clang 6.0: https://wandbox.org/permlink/CSF5ZK8uvZ28AAQu
-
たぶん。未調査 ↩