1

ここで 1 つの質問に答えようとしているときに、次の質問を見つけました。

ポインターを再帰的に逆参照する方法 (C++03)?

回答からの適応コードは次のとおりです。

template<typename T> T& dereference(T &v) { return v; }

template<typename T> const T& dereference(const T &v) { return v; }


template <typename T>
typename std::enable_if<!std::is_pointer<T>::value, T&>::type
dereference(T *v) {
     return dereference(*v);
}

ただし、このテストでは、ポインターからポインターへの逆参照を値の型に失敗しています。

template <typename T>
class A
{
public:
         bool compare(T a, T b){
                return dereference(a) < dereference(b);
        }


};

int main()
{

        int u = 10;
        int *v = &u;
        int **w = &v;

        int i = 5;
        int *j = &i;
        int **k = &j;

        A<int> a;
        A<int*> b;
        A<int**> c;


        std::cout << a.compare(i, u) << std::endl;
        std::cout << b.compare(j, v) << std::endl;


        // This fails - 5 < 10 == 0
        std::cout << **k << " < " <<  **w <<  " == " << c.compare(k, w) << std::endl;


        return 0;

}

明らかに、wandkは 1 回だけ逆参照operator<されるため、2 つのポインターで呼び出されます。

以下を追加することでこれを修正できます。

template <typename T>
typename std::enable_if<!std::is_pointer<T>::value, T&>::type
dereference(T **v) {
     return dereference(*v);
}

しかし、それは失敗しint***ます。

手動でレベルを追加せずにこれを再帰的に行う方法はありますか?

注:これは単なる「理論上の」質問です。

4

2 に答える 2

5

これは、カスタムcan_dereferenceトレイトを使用することで可能になります。

template <typename T>
struct can_dereference_helper {
    template <typename U, typename = decltype(*std::declval<U>())>
    static std::true_type test(U);
    template <typename...U>
    static std::false_type test(U...);
    using type = decltype(test(std::declval<T>()));
};

template <typename T>
struct can_dereference :
  can_dereference_helper<typename std::decay<T>::type>::type {};

そして、少しタグをディスパッチするいくつかの相互再帰関数:

template <typename T>
auto recursive_dereference(T&& t, std::false_type) ->
  decltype(std::forward<T>(t)) {
    return std::forward<T>(t);
}

template <typename T>
auto recursive_dereference(T&& t) ->
  decltype(recursive_dereference(std::forward<T>(t), can_dereference<T>{}));

template <typename T>
auto recursive_dereference(T&& t, std::true_type) ->
  decltype(recursive_dereference(*std::forward<T>(t))) {
    return recursive_dereference(*std::forward<T>(t));
}

template <typename T>
auto recursive_dereference(T&& t) ->
  decltype(recursive_dereference(std::forward<T>(t), can_dereference<T>{})) {
    return recursive_dereference(std::forward<T>(t), can_dereference<T>{});
}

Coliru で実際に動作する様子をご覧ください。これは、Kerrek の回答と比べるとやり過ぎのように思えるかもしれませんが、operator*. どのツールがあなたの問題に最も適しているかを判断させていただきます。

于 2013-11-26T16:55:53.543 に答える
2

最終的な戻り値の型を計算するトレイトを使用してそれを行うことができますremove_all_pointers

#include <type_traits>

template <typename T> struct remove_all_pointers
{ typedef typename std::remove_reference<T>::type type; };
template <typename T> struct remove_all_pointers<T *>
{ typedef typename std::remove_reference<T>::type type; };

template <typename T>
T & dereference(T & p)
{ return p; }

template <typename U>
typename remove_all_pointers<U>::type & dereference(U * p)
{ return dereference(*p); }

int main(int argc, char * argv[])
{
  return dereference(argv);
}

CV バリアントを追加する必要がある場合があります。私はまだそれについて考えています。

于 2013-11-26T16:22:52.790 に答える